diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/settings.gradle b/settings.gradle
index 329f712..3181c92 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-rootProject.name = 'kotlin-webgl-test'
+rootProject.name = 'kudens'
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/settings.gradle b/settings.gradle
index 329f712..3181c92 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-rootProject.name = 'kotlin-webgl-test'
+rootProject.name = 'kudens'
diff --git a/src/com/persesgames/game/Game.kt b/src/com/persesgames/game/Game.kt
new file mode 100644
index 0000000..3abdd56
--- /dev/null
+++ b/src/com/persesgames/game/Game.kt
@@ -0,0 +1,155 @@
+package com.persesgames.game
+
+import com.persesgames.texture.Textures
+import org.khronos.webgl.WebGLRenderingContext
+import org.w3c.dom.CanvasRenderingContext2D
+import org.w3c.dom.HTMLCanvasElement
+import org.w3c.dom.HTMLElement
+import kotlin.browser.document
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+enum class DrawMode {
+ LINEAR,
+ NEAREST
+}
+
+class HTMLElements {
+ var container: HTMLElement
+ var webgl: WebGLRenderingContext
+ var canvas2d: CanvasRenderingContext2D
+
+ init {
+ container = document.createElement("div") as HTMLElement
+
+ val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement
+ val canvas = document.createElement("canvas") as HTMLCanvasElement
+
+ container.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
+ webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" )
+ canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" )
+
+ document.body!!.appendChild(container)
+ container.appendChild(webGlCanvas)
+ container.appendChild(canvas)
+
+ webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext
+ canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D
+ }
+}
+
+object Game {
+ var started = false
+ val view: View = View()
+ val html: HTMLElements by lazy { HTMLElements() }
+ var currentScreen: Screen = DefaultScreen()
+ var start = Date().getTime()
+ var currentTime = start
+ var currentDelta = 0f
+ var pause: Boolean = false
+
+ var fps = 0
+ var fpsCount = 0
+ var fpsCountTime = 0f
+
+ fun gl() = html.webgl
+
+ fun resize() {
+ val canvas = gl().canvas
+
+ // Check if the canvas is not the same size.
+ val windowWidth = window.innerWidth.toInt()
+ val windowHeight = window.innerHeight.toInt()
+
+ if (view.lastWindowWidth != windowWidth ||
+ view.lastWindowHeight != windowHeight) {
+ view.lastWindowWidth = windowWidth
+ view.lastWindowHeight = windowHeight
+ view.windowWidth = windowWidth
+ view.windowHeight = windowHeight
+
+ view.updateView()
+
+ val textCanvas = html.canvas2d.canvas
+
+ // Make the canvas the same size
+ canvas.width = view.width.toInt()
+ canvas.height = view.height.toInt()
+
+ textCanvas.width = view.width.toInt()
+ textCanvas.height = view.height.toInt()
+
+ gl().viewport(0, 0, view.width.toInt(), view.height.toInt())
+
+ val left = (windowWidth - view.windowWidth) / 2
+ val top = (windowHeight - view.windowHeight) / 2
+
+ canvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ textCanvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ }
+ }
+
+ fun start(startScreen: Screen) {
+ if (started) {
+ throw IllegalStateException("You can only start a game once!")
+ }
+
+ setScreen(startScreen)
+
+ // start game loop
+ started = true
+ gameLoop()
+ }
+
+ fun setScreen(screen: Screen) {
+ currentScreen.closeResources()
+
+ currentScreen = screen
+
+ currentScreen.loadResources()
+ }
+
+ fun gameLoop() {
+ if (!Textures.ready()) {
+ Game.gl().clearColor(1f, 1f, 1f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ } else {
+ resize()
+
+ if (!pause) {
+ html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble());
+
+ Game.gl().clearColor(0f, 0f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+
+ Game.gl().enable(WebGLRenderingContext.BLEND);
+ Game.gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA); //ONE_MINUS_DST_ALPHA);
+
+ val time = Date().getTime()
+ currentDelta = (time - currentTime) / 1000f
+ currentTime = time
+
+ val timeInSeconds = (currentTime - start) / 1000f
+
+ fpsCountTime += currentDelta
+ fpsCount++
+ while (fpsCountTime > 1f) {
+ fps = fpsCount
+ fpsCountTime -= 1f
+ fpsCount = 0
+ }
+
+ currentScreen.update(timeInSeconds, currentDelta);
+ currentScreen.render()
+ }
+ }
+
+ window.requestAnimationFrame {
+ gameLoop()
+ }
+ }
+
+}
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/settings.gradle b/settings.gradle
index 329f712..3181c92 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-rootProject.name = 'kotlin-webgl-test'
+rootProject.name = 'kudens'
diff --git a/src/com/persesgames/game/Game.kt b/src/com/persesgames/game/Game.kt
new file mode 100644
index 0000000..3abdd56
--- /dev/null
+++ b/src/com/persesgames/game/Game.kt
@@ -0,0 +1,155 @@
+package com.persesgames.game
+
+import com.persesgames.texture.Textures
+import org.khronos.webgl.WebGLRenderingContext
+import org.w3c.dom.CanvasRenderingContext2D
+import org.w3c.dom.HTMLCanvasElement
+import org.w3c.dom.HTMLElement
+import kotlin.browser.document
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+enum class DrawMode {
+ LINEAR,
+ NEAREST
+}
+
+class HTMLElements {
+ var container: HTMLElement
+ var webgl: WebGLRenderingContext
+ var canvas2d: CanvasRenderingContext2D
+
+ init {
+ container = document.createElement("div") as HTMLElement
+
+ val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement
+ val canvas = document.createElement("canvas") as HTMLCanvasElement
+
+ container.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
+ webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" )
+ canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" )
+
+ document.body!!.appendChild(container)
+ container.appendChild(webGlCanvas)
+ container.appendChild(canvas)
+
+ webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext
+ canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D
+ }
+}
+
+object Game {
+ var started = false
+ val view: View = View()
+ val html: HTMLElements by lazy { HTMLElements() }
+ var currentScreen: Screen = DefaultScreen()
+ var start = Date().getTime()
+ var currentTime = start
+ var currentDelta = 0f
+ var pause: Boolean = false
+
+ var fps = 0
+ var fpsCount = 0
+ var fpsCountTime = 0f
+
+ fun gl() = html.webgl
+
+ fun resize() {
+ val canvas = gl().canvas
+
+ // Check if the canvas is not the same size.
+ val windowWidth = window.innerWidth.toInt()
+ val windowHeight = window.innerHeight.toInt()
+
+ if (view.lastWindowWidth != windowWidth ||
+ view.lastWindowHeight != windowHeight) {
+ view.lastWindowWidth = windowWidth
+ view.lastWindowHeight = windowHeight
+ view.windowWidth = windowWidth
+ view.windowHeight = windowHeight
+
+ view.updateView()
+
+ val textCanvas = html.canvas2d.canvas
+
+ // Make the canvas the same size
+ canvas.width = view.width.toInt()
+ canvas.height = view.height.toInt()
+
+ textCanvas.width = view.width.toInt()
+ textCanvas.height = view.height.toInt()
+
+ gl().viewport(0, 0, view.width.toInt(), view.height.toInt())
+
+ val left = (windowWidth - view.windowWidth) / 2
+ val top = (windowHeight - view.windowHeight) / 2
+
+ canvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ textCanvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ }
+ }
+
+ fun start(startScreen: Screen) {
+ if (started) {
+ throw IllegalStateException("You can only start a game once!")
+ }
+
+ setScreen(startScreen)
+
+ // start game loop
+ started = true
+ gameLoop()
+ }
+
+ fun setScreen(screen: Screen) {
+ currentScreen.closeResources()
+
+ currentScreen = screen
+
+ currentScreen.loadResources()
+ }
+
+ fun gameLoop() {
+ if (!Textures.ready()) {
+ Game.gl().clearColor(1f, 1f, 1f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ } else {
+ resize()
+
+ if (!pause) {
+ html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble());
+
+ Game.gl().clearColor(0f, 0f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+
+ Game.gl().enable(WebGLRenderingContext.BLEND);
+ Game.gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA); //ONE_MINUS_DST_ALPHA);
+
+ val time = Date().getTime()
+ currentDelta = (time - currentTime) / 1000f
+ currentTime = time
+
+ val timeInSeconds = (currentTime - start) / 1000f
+
+ fpsCountTime += currentDelta
+ fpsCount++
+ while (fpsCountTime > 1f) {
+ fps = fpsCount
+ fpsCountTime -= 1f
+ fpsCount = 0
+ }
+
+ currentScreen.update(timeInSeconds, currentDelta);
+ currentScreen.render()
+ }
+ }
+
+ window.requestAnimationFrame {
+ gameLoop()
+ }
+ }
+
+}
diff --git a/src/com/persesgames/game/Screen.kt b/src/com/persesgames/game/Screen.kt
new file mode 100644
index 0000000..6fb558e
--- /dev/null
+++ b/src/com/persesgames/game/Screen.kt
@@ -0,0 +1,35 @@
+package com.persesgames.game
+
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+abstract class Screen {
+
+ open fun loadResources() {
+
+ }
+
+ open fun closeResources() {
+
+ }
+
+ abstract fun update(time: Float, delta: Float)
+
+ abstract fun render()
+
+}
+
+
+class DefaultScreen: Screen() {
+ override fun update(time: Float, delta: Float) {
+ }
+
+ override fun render() {
+ // show loading message?
+ Game.gl().clearColor(1f, 1f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ }
+}
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/settings.gradle b/settings.gradle
index 329f712..3181c92 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-rootProject.name = 'kotlin-webgl-test'
+rootProject.name = 'kudens'
diff --git a/src/com/persesgames/game/Game.kt b/src/com/persesgames/game/Game.kt
new file mode 100644
index 0000000..3abdd56
--- /dev/null
+++ b/src/com/persesgames/game/Game.kt
@@ -0,0 +1,155 @@
+package com.persesgames.game
+
+import com.persesgames.texture.Textures
+import org.khronos.webgl.WebGLRenderingContext
+import org.w3c.dom.CanvasRenderingContext2D
+import org.w3c.dom.HTMLCanvasElement
+import org.w3c.dom.HTMLElement
+import kotlin.browser.document
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+enum class DrawMode {
+ LINEAR,
+ NEAREST
+}
+
+class HTMLElements {
+ var container: HTMLElement
+ var webgl: WebGLRenderingContext
+ var canvas2d: CanvasRenderingContext2D
+
+ init {
+ container = document.createElement("div") as HTMLElement
+
+ val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement
+ val canvas = document.createElement("canvas") as HTMLCanvasElement
+
+ container.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
+ webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" )
+ canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" )
+
+ document.body!!.appendChild(container)
+ container.appendChild(webGlCanvas)
+ container.appendChild(canvas)
+
+ webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext
+ canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D
+ }
+}
+
+object Game {
+ var started = false
+ val view: View = View()
+ val html: HTMLElements by lazy { HTMLElements() }
+ var currentScreen: Screen = DefaultScreen()
+ var start = Date().getTime()
+ var currentTime = start
+ var currentDelta = 0f
+ var pause: Boolean = false
+
+ var fps = 0
+ var fpsCount = 0
+ var fpsCountTime = 0f
+
+ fun gl() = html.webgl
+
+ fun resize() {
+ val canvas = gl().canvas
+
+ // Check if the canvas is not the same size.
+ val windowWidth = window.innerWidth.toInt()
+ val windowHeight = window.innerHeight.toInt()
+
+ if (view.lastWindowWidth != windowWidth ||
+ view.lastWindowHeight != windowHeight) {
+ view.lastWindowWidth = windowWidth
+ view.lastWindowHeight = windowHeight
+ view.windowWidth = windowWidth
+ view.windowHeight = windowHeight
+
+ view.updateView()
+
+ val textCanvas = html.canvas2d.canvas
+
+ // Make the canvas the same size
+ canvas.width = view.width.toInt()
+ canvas.height = view.height.toInt()
+
+ textCanvas.width = view.width.toInt()
+ textCanvas.height = view.height.toInt()
+
+ gl().viewport(0, 0, view.width.toInt(), view.height.toInt())
+
+ val left = (windowWidth - view.windowWidth) / 2
+ val top = (windowHeight - view.windowHeight) / 2
+
+ canvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ textCanvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ }
+ }
+
+ fun start(startScreen: Screen) {
+ if (started) {
+ throw IllegalStateException("You can only start a game once!")
+ }
+
+ setScreen(startScreen)
+
+ // start game loop
+ started = true
+ gameLoop()
+ }
+
+ fun setScreen(screen: Screen) {
+ currentScreen.closeResources()
+
+ currentScreen = screen
+
+ currentScreen.loadResources()
+ }
+
+ fun gameLoop() {
+ if (!Textures.ready()) {
+ Game.gl().clearColor(1f, 1f, 1f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ } else {
+ resize()
+
+ if (!pause) {
+ html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble());
+
+ Game.gl().clearColor(0f, 0f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+
+ Game.gl().enable(WebGLRenderingContext.BLEND);
+ Game.gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA); //ONE_MINUS_DST_ALPHA);
+
+ val time = Date().getTime()
+ currentDelta = (time - currentTime) / 1000f
+ currentTime = time
+
+ val timeInSeconds = (currentTime - start) / 1000f
+
+ fpsCountTime += currentDelta
+ fpsCount++
+ while (fpsCountTime > 1f) {
+ fps = fpsCount
+ fpsCountTime -= 1f
+ fpsCount = 0
+ }
+
+ currentScreen.update(timeInSeconds, currentDelta);
+ currentScreen.render()
+ }
+ }
+
+ window.requestAnimationFrame {
+ gameLoop()
+ }
+ }
+
+}
diff --git a/src/com/persesgames/game/Screen.kt b/src/com/persesgames/game/Screen.kt
new file mode 100644
index 0000000..6fb558e
--- /dev/null
+++ b/src/com/persesgames/game/Screen.kt
@@ -0,0 +1,35 @@
+package com.persesgames.game
+
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+abstract class Screen {
+
+ open fun loadResources() {
+
+ }
+
+ open fun closeResources() {
+
+ }
+
+ abstract fun update(time: Float, delta: Float)
+
+ abstract fun render()
+
+}
+
+
+class DefaultScreen: Screen() {
+ override fun update(time: Float, delta: Float) {
+ }
+
+ override fun render() {
+ // show loading message?
+ Game.gl().clearColor(1f, 1f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/game/View.kt b/src/com/persesgames/game/View.kt
new file mode 100644
index 0000000..e5590e0
--- /dev/null
+++ b/src/com/persesgames/game/View.kt
@@ -0,0 +1,221 @@
+package com.persesgames.game
+
+import com.persesgames.math.Matrix4
+
+enum class ViewType {
+ PROJECTION,
+ WIDTH,
+ HEIGHT,
+ ABSOLUTE
+}
+
+class View(
+ var lastWindowWidth: Int = 2000,
+ var lastWindowHeight: Int = 1000,
+ var windowWidth: Int = 2000,
+ var windowHeight: Int = 1000,
+ var width: Float = 1024f,
+ var height: Float = 1024f,
+ var angle: Float = 60f,
+ var near: Float = -0.1f,
+ var far: Float = -100f,
+ var minAspectRatio: Float = 1f,
+ var maxAspectRatio: Float = 1f,
+ var leftOffset: Int = 0,
+ var bottomOffset: Int = 0,
+ var viewType: ViewType = ViewType.WIDTH,
+ var drawMode: DrawMode = DrawMode.LINEAR) {
+ var vMatrix = Matrix4()
+ var aspectRatio = 1f
+
+ init {
+ updateView()
+ }
+
+ fun requestFullscreen() {
+ println("Requesting fullscreen")
+ js("""
+ if (document.webkitFullscreenElement) {
+ document.webkitCancelFullScreen();
+ } else {
+ document.documentElement.webkitRequestFullScreen();
+ }
+ """)
+ //if (document.fullscreenEnabled) {
+ // println("fullscreen Enabled")
+ //Game.html.container.requestFullscreen()
+ //document.documentElement?.requestFullscreen()
+ //}
+ }
+
+ fun updateView() {
+ aspectRatio = windowWidth / windowHeight.toFloat()
+
+ if (aspectRatio < minAspectRatio) {
+ aspectRatio = minAspectRatio
+
+ windowHeight = (windowWidth / aspectRatio).toInt()
+ }
+
+ if (aspectRatio > maxAspectRatio) {
+ aspectRatio = maxAspectRatio
+
+ windowWidth = (windowHeight * aspectRatio).toInt()
+ }
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.WIDTH -> {
+ height = width / aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.HEIGHT -> {
+ width = height * aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.PROJECTION -> {
+ vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far);
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ //println("width: $width, height: $height")
+ }
+
+ fun screenToGameCoordX(screenX: Float): Float {
+ var result = screenX
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.HEIGHT -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun screenToGameCoordY(screenY: Float): Float {
+ var result = screenY
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.HEIGHT -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordX(gameX: Float): Float {
+ var result = gameX
+ val normalizedX = gameX + (width / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.HEIGHT -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordY(gameY: Float): Float {
+ var result = gameY
+ val normalizedY = gameY + (height / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.HEIGHT -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun setToWidth(width: Float) {
+ this.width = width
+ this.viewType = ViewType.WIDTH
+
+ updateView()
+ }
+
+ fun setToHeight(height: Float) {
+ this.height = height
+ this.viewType = ViewType.HEIGHT
+
+ updateView()
+ }
+
+ fun setProjection(angle: Float) {
+ this.angle = angle
+ this.viewType = ViewType.PROJECTION
+
+ updateView()
+ }
+
+ fun setNear(near: Float) {
+ this.near = near
+
+ updateView()
+ }
+
+ fun setFar(far: Float) {
+ this.far = far
+
+ updateView()
+ }
+}
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/settings.gradle b/settings.gradle
index 329f712..3181c92 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-rootProject.name = 'kotlin-webgl-test'
+rootProject.name = 'kudens'
diff --git a/src/com/persesgames/game/Game.kt b/src/com/persesgames/game/Game.kt
new file mode 100644
index 0000000..3abdd56
--- /dev/null
+++ b/src/com/persesgames/game/Game.kt
@@ -0,0 +1,155 @@
+package com.persesgames.game
+
+import com.persesgames.texture.Textures
+import org.khronos.webgl.WebGLRenderingContext
+import org.w3c.dom.CanvasRenderingContext2D
+import org.w3c.dom.HTMLCanvasElement
+import org.w3c.dom.HTMLElement
+import kotlin.browser.document
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+enum class DrawMode {
+ LINEAR,
+ NEAREST
+}
+
+class HTMLElements {
+ var container: HTMLElement
+ var webgl: WebGLRenderingContext
+ var canvas2d: CanvasRenderingContext2D
+
+ init {
+ container = document.createElement("div") as HTMLElement
+
+ val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement
+ val canvas = document.createElement("canvas") as HTMLCanvasElement
+
+ container.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
+ webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" )
+ canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" )
+
+ document.body!!.appendChild(container)
+ container.appendChild(webGlCanvas)
+ container.appendChild(canvas)
+
+ webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext
+ canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D
+ }
+}
+
+object Game {
+ var started = false
+ val view: View = View()
+ val html: HTMLElements by lazy { HTMLElements() }
+ var currentScreen: Screen = DefaultScreen()
+ var start = Date().getTime()
+ var currentTime = start
+ var currentDelta = 0f
+ var pause: Boolean = false
+
+ var fps = 0
+ var fpsCount = 0
+ var fpsCountTime = 0f
+
+ fun gl() = html.webgl
+
+ fun resize() {
+ val canvas = gl().canvas
+
+ // Check if the canvas is not the same size.
+ val windowWidth = window.innerWidth.toInt()
+ val windowHeight = window.innerHeight.toInt()
+
+ if (view.lastWindowWidth != windowWidth ||
+ view.lastWindowHeight != windowHeight) {
+ view.lastWindowWidth = windowWidth
+ view.lastWindowHeight = windowHeight
+ view.windowWidth = windowWidth
+ view.windowHeight = windowHeight
+
+ view.updateView()
+
+ val textCanvas = html.canvas2d.canvas
+
+ // Make the canvas the same size
+ canvas.width = view.width.toInt()
+ canvas.height = view.height.toInt()
+
+ textCanvas.width = view.width.toInt()
+ textCanvas.height = view.height.toInt()
+
+ gl().viewport(0, 0, view.width.toInt(), view.height.toInt())
+
+ val left = (windowWidth - view.windowWidth) / 2
+ val top = (windowHeight - view.windowHeight) / 2
+
+ canvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ textCanvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ }
+ }
+
+ fun start(startScreen: Screen) {
+ if (started) {
+ throw IllegalStateException("You can only start a game once!")
+ }
+
+ setScreen(startScreen)
+
+ // start game loop
+ started = true
+ gameLoop()
+ }
+
+ fun setScreen(screen: Screen) {
+ currentScreen.closeResources()
+
+ currentScreen = screen
+
+ currentScreen.loadResources()
+ }
+
+ fun gameLoop() {
+ if (!Textures.ready()) {
+ Game.gl().clearColor(1f, 1f, 1f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ } else {
+ resize()
+
+ if (!pause) {
+ html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble());
+
+ Game.gl().clearColor(0f, 0f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+
+ Game.gl().enable(WebGLRenderingContext.BLEND);
+ Game.gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA); //ONE_MINUS_DST_ALPHA);
+
+ val time = Date().getTime()
+ currentDelta = (time - currentTime) / 1000f
+ currentTime = time
+
+ val timeInSeconds = (currentTime - start) / 1000f
+
+ fpsCountTime += currentDelta
+ fpsCount++
+ while (fpsCountTime > 1f) {
+ fps = fpsCount
+ fpsCountTime -= 1f
+ fpsCount = 0
+ }
+
+ currentScreen.update(timeInSeconds, currentDelta);
+ currentScreen.render()
+ }
+ }
+
+ window.requestAnimationFrame {
+ gameLoop()
+ }
+ }
+
+}
diff --git a/src/com/persesgames/game/Screen.kt b/src/com/persesgames/game/Screen.kt
new file mode 100644
index 0000000..6fb558e
--- /dev/null
+++ b/src/com/persesgames/game/Screen.kt
@@ -0,0 +1,35 @@
+package com.persesgames.game
+
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+abstract class Screen {
+
+ open fun loadResources() {
+
+ }
+
+ open fun closeResources() {
+
+ }
+
+ abstract fun update(time: Float, delta: Float)
+
+ abstract fun render()
+
+}
+
+
+class DefaultScreen: Screen() {
+ override fun update(time: Float, delta: Float) {
+ }
+
+ override fun render() {
+ // show loading message?
+ Game.gl().clearColor(1f, 1f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/game/View.kt b/src/com/persesgames/game/View.kt
new file mode 100644
index 0000000..e5590e0
--- /dev/null
+++ b/src/com/persesgames/game/View.kt
@@ -0,0 +1,221 @@
+package com.persesgames.game
+
+import com.persesgames.math.Matrix4
+
+enum class ViewType {
+ PROJECTION,
+ WIDTH,
+ HEIGHT,
+ ABSOLUTE
+}
+
+class View(
+ var lastWindowWidth: Int = 2000,
+ var lastWindowHeight: Int = 1000,
+ var windowWidth: Int = 2000,
+ var windowHeight: Int = 1000,
+ var width: Float = 1024f,
+ var height: Float = 1024f,
+ var angle: Float = 60f,
+ var near: Float = -0.1f,
+ var far: Float = -100f,
+ var minAspectRatio: Float = 1f,
+ var maxAspectRatio: Float = 1f,
+ var leftOffset: Int = 0,
+ var bottomOffset: Int = 0,
+ var viewType: ViewType = ViewType.WIDTH,
+ var drawMode: DrawMode = DrawMode.LINEAR) {
+ var vMatrix = Matrix4()
+ var aspectRatio = 1f
+
+ init {
+ updateView()
+ }
+
+ fun requestFullscreen() {
+ println("Requesting fullscreen")
+ js("""
+ if (document.webkitFullscreenElement) {
+ document.webkitCancelFullScreen();
+ } else {
+ document.documentElement.webkitRequestFullScreen();
+ }
+ """)
+ //if (document.fullscreenEnabled) {
+ // println("fullscreen Enabled")
+ //Game.html.container.requestFullscreen()
+ //document.documentElement?.requestFullscreen()
+ //}
+ }
+
+ fun updateView() {
+ aspectRatio = windowWidth / windowHeight.toFloat()
+
+ if (aspectRatio < minAspectRatio) {
+ aspectRatio = minAspectRatio
+
+ windowHeight = (windowWidth / aspectRatio).toInt()
+ }
+
+ if (aspectRatio > maxAspectRatio) {
+ aspectRatio = maxAspectRatio
+
+ windowWidth = (windowHeight * aspectRatio).toInt()
+ }
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.WIDTH -> {
+ height = width / aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.HEIGHT -> {
+ width = height * aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.PROJECTION -> {
+ vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far);
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ //println("width: $width, height: $height")
+ }
+
+ fun screenToGameCoordX(screenX: Float): Float {
+ var result = screenX
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.HEIGHT -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun screenToGameCoordY(screenY: Float): Float {
+ var result = screenY
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.HEIGHT -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordX(gameX: Float): Float {
+ var result = gameX
+ val normalizedX = gameX + (width / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.HEIGHT -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordY(gameY: Float): Float {
+ var result = gameY
+ val normalizedY = gameY + (height / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.HEIGHT -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun setToWidth(width: Float) {
+ this.width = width
+ this.viewType = ViewType.WIDTH
+
+ updateView()
+ }
+
+ fun setToHeight(height: Float) {
+ this.height = height
+ this.viewType = ViewType.HEIGHT
+
+ updateView()
+ }
+
+ fun setProjection(angle: Float) {
+ this.angle = angle
+ this.viewType = ViewType.PROJECTION
+
+ updateView()
+ }
+
+ fun setNear(near: Float) {
+ this.near = near
+
+ updateView()
+ }
+
+ fun setFar(far: Float) {
+ this.far = far
+
+ updateView()
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/input/Keys.kt b/src/com/persesgames/input/Keys.kt
new file mode 100644
index 0000000..6705c67
--- /dev/null
+++ b/src/com/persesgames/input/Keys.kt
@@ -0,0 +1,141 @@
+package com.persesgames.input
+
+import com.persesgames.game.Game
+import org.w3c.dom.events.Event
+import org.w3c.dom.events.KeyboardEvent
+import org.w3c.dom.events.MouseEvent
+import java.util.*
+import kotlin.browser.document
+import kotlin.dom.on
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 12:18
+ */
+
+enum class KeyCode(val keyCode: Int) {
+ LEFT(37),
+ UP(38),
+ DOWN(40),
+ RIGHT(39),
+ SPACE(32),
+ MINUS(109),
+ PLUS(107),
+}
+
+interface InputProcessor {
+
+ fun keyPressed(charCode: Int)
+
+ fun keyDown(keyCode: Int)
+
+ fun keyUp(keyCode: Int)
+
+ fun pointerClick(pointer: Int, x: Float, y: Float)
+
+}
+
+open class EmptyInputProcessor : InputProcessor {
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ }
+
+ override fun keyDown(keyCode: Int) {
+ }
+
+ override fun keyPressed(charCode: Int) {
+ }
+
+ override fun keyUp(keyCode: Int) {
+ }
+
+
+}
+
+object Keys {
+
+ private val keys: MutableMap = HashMap();
+ private var inputProcesser: InputProcessor = EmptyInputProcessor()
+
+ init {
+ val body = document.body
+ if (body != null) {
+ body.on("keydown", true) {
+ Keys.keyDown(it)
+ }
+
+ body.on("keyup", true) {
+ Keys.keyUp(it)
+ }
+
+ body.on("keypress", true) {
+ Keys.keyPress(it)
+ }
+
+ body.on("click", true) {
+ Keys.mouseClick(it)
+ }
+
+ body.on("mousedown", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mouseup", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mousemove", true) {
+ Keys.mouseMove(it)
+ }
+ }
+ }
+
+ fun setInputProcessor(processor: InputProcessor) {
+ this.inputProcesser = processor
+ }
+
+ private fun keyDown(key: Event) {
+ if (key is KeyboardEvent) {
+ keys.put(key.keyCode, Date().getTime())
+
+ inputProcesser.keyDown(key.keyCode)
+ }
+ }
+
+ private fun keyUp(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyUp(key.keyCode)
+
+ keys.remove(key.keyCode)
+ }
+ }
+
+ private fun keyPress(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyPressed(key.charCode)
+ }
+ }
+
+ private fun mouseClick(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+ inputProcesser.pointerClick(event.button.toInt(), vx, vy)
+ }
+ }
+
+ private fun mouseMove(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+
+ }
+ }
+
+ fun isDown(keyCode: Int) = keys.containsKey(keyCode)
+
+ fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode)
+
+}
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/settings.gradle b/settings.gradle
index 329f712..3181c92 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-rootProject.name = 'kotlin-webgl-test'
+rootProject.name = 'kudens'
diff --git a/src/com/persesgames/game/Game.kt b/src/com/persesgames/game/Game.kt
new file mode 100644
index 0000000..3abdd56
--- /dev/null
+++ b/src/com/persesgames/game/Game.kt
@@ -0,0 +1,155 @@
+package com.persesgames.game
+
+import com.persesgames.texture.Textures
+import org.khronos.webgl.WebGLRenderingContext
+import org.w3c.dom.CanvasRenderingContext2D
+import org.w3c.dom.HTMLCanvasElement
+import org.w3c.dom.HTMLElement
+import kotlin.browser.document
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+enum class DrawMode {
+ LINEAR,
+ NEAREST
+}
+
+class HTMLElements {
+ var container: HTMLElement
+ var webgl: WebGLRenderingContext
+ var canvas2d: CanvasRenderingContext2D
+
+ init {
+ container = document.createElement("div") as HTMLElement
+
+ val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement
+ val canvas = document.createElement("canvas") as HTMLCanvasElement
+
+ container.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
+ webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" )
+ canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" )
+
+ document.body!!.appendChild(container)
+ container.appendChild(webGlCanvas)
+ container.appendChild(canvas)
+
+ webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext
+ canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D
+ }
+}
+
+object Game {
+ var started = false
+ val view: View = View()
+ val html: HTMLElements by lazy { HTMLElements() }
+ var currentScreen: Screen = DefaultScreen()
+ var start = Date().getTime()
+ var currentTime = start
+ var currentDelta = 0f
+ var pause: Boolean = false
+
+ var fps = 0
+ var fpsCount = 0
+ var fpsCountTime = 0f
+
+ fun gl() = html.webgl
+
+ fun resize() {
+ val canvas = gl().canvas
+
+ // Check if the canvas is not the same size.
+ val windowWidth = window.innerWidth.toInt()
+ val windowHeight = window.innerHeight.toInt()
+
+ if (view.lastWindowWidth != windowWidth ||
+ view.lastWindowHeight != windowHeight) {
+ view.lastWindowWidth = windowWidth
+ view.lastWindowHeight = windowHeight
+ view.windowWidth = windowWidth
+ view.windowHeight = windowHeight
+
+ view.updateView()
+
+ val textCanvas = html.canvas2d.canvas
+
+ // Make the canvas the same size
+ canvas.width = view.width.toInt()
+ canvas.height = view.height.toInt()
+
+ textCanvas.width = view.width.toInt()
+ textCanvas.height = view.height.toInt()
+
+ gl().viewport(0, 0, view.width.toInt(), view.height.toInt())
+
+ val left = (windowWidth - view.windowWidth) / 2
+ val top = (windowHeight - view.windowHeight) / 2
+
+ canvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ textCanvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ }
+ }
+
+ fun start(startScreen: Screen) {
+ if (started) {
+ throw IllegalStateException("You can only start a game once!")
+ }
+
+ setScreen(startScreen)
+
+ // start game loop
+ started = true
+ gameLoop()
+ }
+
+ fun setScreen(screen: Screen) {
+ currentScreen.closeResources()
+
+ currentScreen = screen
+
+ currentScreen.loadResources()
+ }
+
+ fun gameLoop() {
+ if (!Textures.ready()) {
+ Game.gl().clearColor(1f, 1f, 1f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ } else {
+ resize()
+
+ if (!pause) {
+ html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble());
+
+ Game.gl().clearColor(0f, 0f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+
+ Game.gl().enable(WebGLRenderingContext.BLEND);
+ Game.gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA); //ONE_MINUS_DST_ALPHA);
+
+ val time = Date().getTime()
+ currentDelta = (time - currentTime) / 1000f
+ currentTime = time
+
+ val timeInSeconds = (currentTime - start) / 1000f
+
+ fpsCountTime += currentDelta
+ fpsCount++
+ while (fpsCountTime > 1f) {
+ fps = fpsCount
+ fpsCountTime -= 1f
+ fpsCount = 0
+ }
+
+ currentScreen.update(timeInSeconds, currentDelta);
+ currentScreen.render()
+ }
+ }
+
+ window.requestAnimationFrame {
+ gameLoop()
+ }
+ }
+
+}
diff --git a/src/com/persesgames/game/Screen.kt b/src/com/persesgames/game/Screen.kt
new file mode 100644
index 0000000..6fb558e
--- /dev/null
+++ b/src/com/persesgames/game/Screen.kt
@@ -0,0 +1,35 @@
+package com.persesgames.game
+
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+abstract class Screen {
+
+ open fun loadResources() {
+
+ }
+
+ open fun closeResources() {
+
+ }
+
+ abstract fun update(time: Float, delta: Float)
+
+ abstract fun render()
+
+}
+
+
+class DefaultScreen: Screen() {
+ override fun update(time: Float, delta: Float) {
+ }
+
+ override fun render() {
+ // show loading message?
+ Game.gl().clearColor(1f, 1f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/game/View.kt b/src/com/persesgames/game/View.kt
new file mode 100644
index 0000000..e5590e0
--- /dev/null
+++ b/src/com/persesgames/game/View.kt
@@ -0,0 +1,221 @@
+package com.persesgames.game
+
+import com.persesgames.math.Matrix4
+
+enum class ViewType {
+ PROJECTION,
+ WIDTH,
+ HEIGHT,
+ ABSOLUTE
+}
+
+class View(
+ var lastWindowWidth: Int = 2000,
+ var lastWindowHeight: Int = 1000,
+ var windowWidth: Int = 2000,
+ var windowHeight: Int = 1000,
+ var width: Float = 1024f,
+ var height: Float = 1024f,
+ var angle: Float = 60f,
+ var near: Float = -0.1f,
+ var far: Float = -100f,
+ var minAspectRatio: Float = 1f,
+ var maxAspectRatio: Float = 1f,
+ var leftOffset: Int = 0,
+ var bottomOffset: Int = 0,
+ var viewType: ViewType = ViewType.WIDTH,
+ var drawMode: DrawMode = DrawMode.LINEAR) {
+ var vMatrix = Matrix4()
+ var aspectRatio = 1f
+
+ init {
+ updateView()
+ }
+
+ fun requestFullscreen() {
+ println("Requesting fullscreen")
+ js("""
+ if (document.webkitFullscreenElement) {
+ document.webkitCancelFullScreen();
+ } else {
+ document.documentElement.webkitRequestFullScreen();
+ }
+ """)
+ //if (document.fullscreenEnabled) {
+ // println("fullscreen Enabled")
+ //Game.html.container.requestFullscreen()
+ //document.documentElement?.requestFullscreen()
+ //}
+ }
+
+ fun updateView() {
+ aspectRatio = windowWidth / windowHeight.toFloat()
+
+ if (aspectRatio < minAspectRatio) {
+ aspectRatio = minAspectRatio
+
+ windowHeight = (windowWidth / aspectRatio).toInt()
+ }
+
+ if (aspectRatio > maxAspectRatio) {
+ aspectRatio = maxAspectRatio
+
+ windowWidth = (windowHeight * aspectRatio).toInt()
+ }
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.WIDTH -> {
+ height = width / aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.HEIGHT -> {
+ width = height * aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.PROJECTION -> {
+ vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far);
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ //println("width: $width, height: $height")
+ }
+
+ fun screenToGameCoordX(screenX: Float): Float {
+ var result = screenX
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.HEIGHT -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun screenToGameCoordY(screenY: Float): Float {
+ var result = screenY
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.HEIGHT -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordX(gameX: Float): Float {
+ var result = gameX
+ val normalizedX = gameX + (width / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.HEIGHT -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordY(gameY: Float): Float {
+ var result = gameY
+ val normalizedY = gameY + (height / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.HEIGHT -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun setToWidth(width: Float) {
+ this.width = width
+ this.viewType = ViewType.WIDTH
+
+ updateView()
+ }
+
+ fun setToHeight(height: Float) {
+ this.height = height
+ this.viewType = ViewType.HEIGHT
+
+ updateView()
+ }
+
+ fun setProjection(angle: Float) {
+ this.angle = angle
+ this.viewType = ViewType.PROJECTION
+
+ updateView()
+ }
+
+ fun setNear(near: Float) {
+ this.near = near
+
+ updateView()
+ }
+
+ fun setFar(far: Float) {
+ this.far = far
+
+ updateView()
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/input/Keys.kt b/src/com/persesgames/input/Keys.kt
new file mode 100644
index 0000000..6705c67
--- /dev/null
+++ b/src/com/persesgames/input/Keys.kt
@@ -0,0 +1,141 @@
+package com.persesgames.input
+
+import com.persesgames.game.Game
+import org.w3c.dom.events.Event
+import org.w3c.dom.events.KeyboardEvent
+import org.w3c.dom.events.MouseEvent
+import java.util.*
+import kotlin.browser.document
+import kotlin.dom.on
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 12:18
+ */
+
+enum class KeyCode(val keyCode: Int) {
+ LEFT(37),
+ UP(38),
+ DOWN(40),
+ RIGHT(39),
+ SPACE(32),
+ MINUS(109),
+ PLUS(107),
+}
+
+interface InputProcessor {
+
+ fun keyPressed(charCode: Int)
+
+ fun keyDown(keyCode: Int)
+
+ fun keyUp(keyCode: Int)
+
+ fun pointerClick(pointer: Int, x: Float, y: Float)
+
+}
+
+open class EmptyInputProcessor : InputProcessor {
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ }
+
+ override fun keyDown(keyCode: Int) {
+ }
+
+ override fun keyPressed(charCode: Int) {
+ }
+
+ override fun keyUp(keyCode: Int) {
+ }
+
+
+}
+
+object Keys {
+
+ private val keys: MutableMap = HashMap();
+ private var inputProcesser: InputProcessor = EmptyInputProcessor()
+
+ init {
+ val body = document.body
+ if (body != null) {
+ body.on("keydown", true) {
+ Keys.keyDown(it)
+ }
+
+ body.on("keyup", true) {
+ Keys.keyUp(it)
+ }
+
+ body.on("keypress", true) {
+ Keys.keyPress(it)
+ }
+
+ body.on("click", true) {
+ Keys.mouseClick(it)
+ }
+
+ body.on("mousedown", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mouseup", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mousemove", true) {
+ Keys.mouseMove(it)
+ }
+ }
+ }
+
+ fun setInputProcessor(processor: InputProcessor) {
+ this.inputProcesser = processor
+ }
+
+ private fun keyDown(key: Event) {
+ if (key is KeyboardEvent) {
+ keys.put(key.keyCode, Date().getTime())
+
+ inputProcesser.keyDown(key.keyCode)
+ }
+ }
+
+ private fun keyUp(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyUp(key.keyCode)
+
+ keys.remove(key.keyCode)
+ }
+ }
+
+ private fun keyPress(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyPressed(key.charCode)
+ }
+ }
+
+ private fun mouseClick(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+ inputProcesser.pointerClick(event.button.toInt(), vx, vy)
+ }
+ }
+
+ private fun mouseMove(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+
+ }
+ }
+
+ fun isDown(keyCode: Int) = keys.containsKey(keyCode)
+
+ fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode)
+
+}
diff --git a/src/com/persesgames/map/Map.kt b/src/com/persesgames/map/Map.kt
new file mode 100644
index 0000000..b5d7bc8
--- /dev/null
+++ b/src/com/persesgames/map/Map.kt
@@ -0,0 +1,9 @@
+package com.persesgames.map
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+open class Map {
+
+}
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/settings.gradle b/settings.gradle
index 329f712..3181c92 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-rootProject.name = 'kotlin-webgl-test'
+rootProject.name = 'kudens'
diff --git a/src/com/persesgames/game/Game.kt b/src/com/persesgames/game/Game.kt
new file mode 100644
index 0000000..3abdd56
--- /dev/null
+++ b/src/com/persesgames/game/Game.kt
@@ -0,0 +1,155 @@
+package com.persesgames.game
+
+import com.persesgames.texture.Textures
+import org.khronos.webgl.WebGLRenderingContext
+import org.w3c.dom.CanvasRenderingContext2D
+import org.w3c.dom.HTMLCanvasElement
+import org.w3c.dom.HTMLElement
+import kotlin.browser.document
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+enum class DrawMode {
+ LINEAR,
+ NEAREST
+}
+
+class HTMLElements {
+ var container: HTMLElement
+ var webgl: WebGLRenderingContext
+ var canvas2d: CanvasRenderingContext2D
+
+ init {
+ container = document.createElement("div") as HTMLElement
+
+ val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement
+ val canvas = document.createElement("canvas") as HTMLCanvasElement
+
+ container.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
+ webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" )
+ canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" )
+
+ document.body!!.appendChild(container)
+ container.appendChild(webGlCanvas)
+ container.appendChild(canvas)
+
+ webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext
+ canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D
+ }
+}
+
+object Game {
+ var started = false
+ val view: View = View()
+ val html: HTMLElements by lazy { HTMLElements() }
+ var currentScreen: Screen = DefaultScreen()
+ var start = Date().getTime()
+ var currentTime = start
+ var currentDelta = 0f
+ var pause: Boolean = false
+
+ var fps = 0
+ var fpsCount = 0
+ var fpsCountTime = 0f
+
+ fun gl() = html.webgl
+
+ fun resize() {
+ val canvas = gl().canvas
+
+ // Check if the canvas is not the same size.
+ val windowWidth = window.innerWidth.toInt()
+ val windowHeight = window.innerHeight.toInt()
+
+ if (view.lastWindowWidth != windowWidth ||
+ view.lastWindowHeight != windowHeight) {
+ view.lastWindowWidth = windowWidth
+ view.lastWindowHeight = windowHeight
+ view.windowWidth = windowWidth
+ view.windowHeight = windowHeight
+
+ view.updateView()
+
+ val textCanvas = html.canvas2d.canvas
+
+ // Make the canvas the same size
+ canvas.width = view.width.toInt()
+ canvas.height = view.height.toInt()
+
+ textCanvas.width = view.width.toInt()
+ textCanvas.height = view.height.toInt()
+
+ gl().viewport(0, 0, view.width.toInt(), view.height.toInt())
+
+ val left = (windowWidth - view.windowWidth) / 2
+ val top = (windowHeight - view.windowHeight) / 2
+
+ canvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ textCanvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ }
+ }
+
+ fun start(startScreen: Screen) {
+ if (started) {
+ throw IllegalStateException("You can only start a game once!")
+ }
+
+ setScreen(startScreen)
+
+ // start game loop
+ started = true
+ gameLoop()
+ }
+
+ fun setScreen(screen: Screen) {
+ currentScreen.closeResources()
+
+ currentScreen = screen
+
+ currentScreen.loadResources()
+ }
+
+ fun gameLoop() {
+ if (!Textures.ready()) {
+ Game.gl().clearColor(1f, 1f, 1f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ } else {
+ resize()
+
+ if (!pause) {
+ html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble());
+
+ Game.gl().clearColor(0f, 0f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+
+ Game.gl().enable(WebGLRenderingContext.BLEND);
+ Game.gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA); //ONE_MINUS_DST_ALPHA);
+
+ val time = Date().getTime()
+ currentDelta = (time - currentTime) / 1000f
+ currentTime = time
+
+ val timeInSeconds = (currentTime - start) / 1000f
+
+ fpsCountTime += currentDelta
+ fpsCount++
+ while (fpsCountTime > 1f) {
+ fps = fpsCount
+ fpsCountTime -= 1f
+ fpsCount = 0
+ }
+
+ currentScreen.update(timeInSeconds, currentDelta);
+ currentScreen.render()
+ }
+ }
+
+ window.requestAnimationFrame {
+ gameLoop()
+ }
+ }
+
+}
diff --git a/src/com/persesgames/game/Screen.kt b/src/com/persesgames/game/Screen.kt
new file mode 100644
index 0000000..6fb558e
--- /dev/null
+++ b/src/com/persesgames/game/Screen.kt
@@ -0,0 +1,35 @@
+package com.persesgames.game
+
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+abstract class Screen {
+
+ open fun loadResources() {
+
+ }
+
+ open fun closeResources() {
+
+ }
+
+ abstract fun update(time: Float, delta: Float)
+
+ abstract fun render()
+
+}
+
+
+class DefaultScreen: Screen() {
+ override fun update(time: Float, delta: Float) {
+ }
+
+ override fun render() {
+ // show loading message?
+ Game.gl().clearColor(1f, 1f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/game/View.kt b/src/com/persesgames/game/View.kt
new file mode 100644
index 0000000..e5590e0
--- /dev/null
+++ b/src/com/persesgames/game/View.kt
@@ -0,0 +1,221 @@
+package com.persesgames.game
+
+import com.persesgames.math.Matrix4
+
+enum class ViewType {
+ PROJECTION,
+ WIDTH,
+ HEIGHT,
+ ABSOLUTE
+}
+
+class View(
+ var lastWindowWidth: Int = 2000,
+ var lastWindowHeight: Int = 1000,
+ var windowWidth: Int = 2000,
+ var windowHeight: Int = 1000,
+ var width: Float = 1024f,
+ var height: Float = 1024f,
+ var angle: Float = 60f,
+ var near: Float = -0.1f,
+ var far: Float = -100f,
+ var minAspectRatio: Float = 1f,
+ var maxAspectRatio: Float = 1f,
+ var leftOffset: Int = 0,
+ var bottomOffset: Int = 0,
+ var viewType: ViewType = ViewType.WIDTH,
+ var drawMode: DrawMode = DrawMode.LINEAR) {
+ var vMatrix = Matrix4()
+ var aspectRatio = 1f
+
+ init {
+ updateView()
+ }
+
+ fun requestFullscreen() {
+ println("Requesting fullscreen")
+ js("""
+ if (document.webkitFullscreenElement) {
+ document.webkitCancelFullScreen();
+ } else {
+ document.documentElement.webkitRequestFullScreen();
+ }
+ """)
+ //if (document.fullscreenEnabled) {
+ // println("fullscreen Enabled")
+ //Game.html.container.requestFullscreen()
+ //document.documentElement?.requestFullscreen()
+ //}
+ }
+
+ fun updateView() {
+ aspectRatio = windowWidth / windowHeight.toFloat()
+
+ if (aspectRatio < minAspectRatio) {
+ aspectRatio = minAspectRatio
+
+ windowHeight = (windowWidth / aspectRatio).toInt()
+ }
+
+ if (aspectRatio > maxAspectRatio) {
+ aspectRatio = maxAspectRatio
+
+ windowWidth = (windowHeight * aspectRatio).toInt()
+ }
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.WIDTH -> {
+ height = width / aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.HEIGHT -> {
+ width = height * aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.PROJECTION -> {
+ vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far);
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ //println("width: $width, height: $height")
+ }
+
+ fun screenToGameCoordX(screenX: Float): Float {
+ var result = screenX
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.HEIGHT -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun screenToGameCoordY(screenY: Float): Float {
+ var result = screenY
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.HEIGHT -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordX(gameX: Float): Float {
+ var result = gameX
+ val normalizedX = gameX + (width / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.HEIGHT -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordY(gameY: Float): Float {
+ var result = gameY
+ val normalizedY = gameY + (height / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.HEIGHT -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun setToWidth(width: Float) {
+ this.width = width
+ this.viewType = ViewType.WIDTH
+
+ updateView()
+ }
+
+ fun setToHeight(height: Float) {
+ this.height = height
+ this.viewType = ViewType.HEIGHT
+
+ updateView()
+ }
+
+ fun setProjection(angle: Float) {
+ this.angle = angle
+ this.viewType = ViewType.PROJECTION
+
+ updateView()
+ }
+
+ fun setNear(near: Float) {
+ this.near = near
+
+ updateView()
+ }
+
+ fun setFar(far: Float) {
+ this.far = far
+
+ updateView()
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/input/Keys.kt b/src/com/persesgames/input/Keys.kt
new file mode 100644
index 0000000..6705c67
--- /dev/null
+++ b/src/com/persesgames/input/Keys.kt
@@ -0,0 +1,141 @@
+package com.persesgames.input
+
+import com.persesgames.game.Game
+import org.w3c.dom.events.Event
+import org.w3c.dom.events.KeyboardEvent
+import org.w3c.dom.events.MouseEvent
+import java.util.*
+import kotlin.browser.document
+import kotlin.dom.on
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 12:18
+ */
+
+enum class KeyCode(val keyCode: Int) {
+ LEFT(37),
+ UP(38),
+ DOWN(40),
+ RIGHT(39),
+ SPACE(32),
+ MINUS(109),
+ PLUS(107),
+}
+
+interface InputProcessor {
+
+ fun keyPressed(charCode: Int)
+
+ fun keyDown(keyCode: Int)
+
+ fun keyUp(keyCode: Int)
+
+ fun pointerClick(pointer: Int, x: Float, y: Float)
+
+}
+
+open class EmptyInputProcessor : InputProcessor {
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ }
+
+ override fun keyDown(keyCode: Int) {
+ }
+
+ override fun keyPressed(charCode: Int) {
+ }
+
+ override fun keyUp(keyCode: Int) {
+ }
+
+
+}
+
+object Keys {
+
+ private val keys: MutableMap = HashMap();
+ private var inputProcesser: InputProcessor = EmptyInputProcessor()
+
+ init {
+ val body = document.body
+ if (body != null) {
+ body.on("keydown", true) {
+ Keys.keyDown(it)
+ }
+
+ body.on("keyup", true) {
+ Keys.keyUp(it)
+ }
+
+ body.on("keypress", true) {
+ Keys.keyPress(it)
+ }
+
+ body.on("click", true) {
+ Keys.mouseClick(it)
+ }
+
+ body.on("mousedown", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mouseup", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mousemove", true) {
+ Keys.mouseMove(it)
+ }
+ }
+ }
+
+ fun setInputProcessor(processor: InputProcessor) {
+ this.inputProcesser = processor
+ }
+
+ private fun keyDown(key: Event) {
+ if (key is KeyboardEvent) {
+ keys.put(key.keyCode, Date().getTime())
+
+ inputProcesser.keyDown(key.keyCode)
+ }
+ }
+
+ private fun keyUp(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyUp(key.keyCode)
+
+ keys.remove(key.keyCode)
+ }
+ }
+
+ private fun keyPress(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyPressed(key.charCode)
+ }
+ }
+
+ private fun mouseClick(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+ inputProcesser.pointerClick(event.button.toInt(), vx, vy)
+ }
+ }
+
+ private fun mouseMove(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+
+ }
+ }
+
+ fun isDown(keyCode: Int) = keys.containsKey(keyCode)
+
+ fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode)
+
+}
diff --git a/src/com/persesgames/map/Map.kt b/src/com/persesgames/map/Map.kt
new file mode 100644
index 0000000..b5d7bc8
--- /dev/null
+++ b/src/com/persesgames/map/Map.kt
@@ -0,0 +1,9 @@
+package com.persesgames.map
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+open class Map {
+
+}
diff --git a/src/com/persesgames/map/tiled/TiledMap.kt b/src/com/persesgames/map/tiled/TiledMap.kt
new file mode 100644
index 0000000..a84a5a3
--- /dev/null
+++ b/src/com/persesgames/map/tiled/TiledMap.kt
@@ -0,0 +1,211 @@
+package com.persesgames.map.tiled
+
+import com.persesgames.net.getUrlAsString
+import com.persesgames.texture.Texture
+import com.persesgames.texture.Textures
+import java.util.*
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+class MapData {
+ var version: Int = 1
+ var properties: MutableMap = HashMap()
+ var layers: Array? = null
+ var tilesets: Array? = null
+
+ var height: Int = 0
+ var width: Int = 0
+
+ var nextobjectid: Int = 0
+ var orientation: String = "orthogonal"
+ var renderorder: String = "right-down"
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+}
+
+class MapLayer {
+ var properties: MutableMap = HashMap()
+
+ var data: Array? = null
+ var encoding: String = ""
+ var x: Int = 0
+ var y: Int = 0
+ var width: Int = 0
+ var height: Int = 0
+ var name: String = ""
+ var opacity: Float = 1f
+ var type: String = ""
+ var visible: Boolean = true
+ var draworder: String = ""
+}
+
+class MapTileset {
+ var properties: MutableMap = HashMap()
+
+ var firstgid: Int = 0
+ var image: String = ""
+ var imageheight: Int = 0
+ var imagewidth: Int = 0
+ var margin: Int = 0
+ var name: String = ""
+ var spacing: Int = 0
+ var tilecount: Int = 0
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+ var tileproperties: MutableMap> = HashMap()
+}
+
+class TilesetIndex(
+ val texture: Texture?,
+ val tcLeft: Float,
+ val tcTop: Float,
+ val tcRight: Float,
+ val tcBottom: Float,
+ val scale: Float
+ ) {
+ constructor() : this(null, 0f, 0f, 0f, 0f, 0f)
+
+ fun render(x: Float, y: Float) {
+ texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+}
+
+class TiledMap(dir: String = "", url: String) {
+ val properties: Map = HashMap()
+ val data: MapData
+ val tileset: Array
+ val tiles: Array
+ var first = true
+ //var tilesetIndex: Array = Array(0, { TilesetIndex() })
+
+ init {
+ var tileDir = dir
+ if (!tileDir.isEmpty() && !tileDir.endsWith("/")) {
+ tileDir = tileDir + "/"
+ }
+
+ data = JSON.parse(getUrlAsString(tileDir + url))
+ println("map data is loaded")
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ tileset = Array(tilesets.size, { "" })
+ var maxGid = 0
+ for (index in 0..tilesets.size - 1) {
+ tileset[index] = tilesets[index].name
+ Textures.load(tilesets[index].name, tileDir + tilesets[index].image)
+ maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount)
+ }
+
+ tiles = Array(maxGid, { TilesetIndex() })
+ } else {
+ tileset = Array(0, { "" })
+ tiles = Array(0, { TilesetIndex() })
+ }
+
+ cacheTiles()
+ }
+
+ fun cacheTiles() {
+ if (!Textures.ready()) {
+ window.setTimeout({ cacheTiles() }, 10)
+ } else {
+ val tilesets = data.tilesets
+ var tcLeft = 0f
+ var tcTop = 0f
+ var tcRight = 0f
+ var tcBottom = 0f
+
+ if (tilesets != null) {
+
+
+ for (tileset in tilesets) {
+ val tilesHor = tileset.imagewidth / tileset.tilewidth
+ val tilesVer = tileset.imageheight / tileset.tileheight
+ val scale = (tileset.tilewidth / tileset.imagewidth.toFloat())
+
+ for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) {
+ val texture = Textures.get(tileset.name)
+
+ val gid = index - tileset.firstgid
+
+ val xi = gid % tilesHor
+ var yi = gid / tilesHor
+ yi = tilesVer - yi - 1
+ val tw = 1f / tilesHor.toFloat()
+ val th = 1f / tilesVer.toFloat()
+
+ val pixelW = 0.1f / tileset.tilewidth
+ val pixelH = 0.1f / tileset.tileheight
+
+ tcLeft = xi * tw
+ tcRight = tcLeft + tw
+
+ // switch up/down because of texture coord 0,0 in left bottom corner
+ tcBottom = yi * th
+ tcTop = tcBottom + th
+
+ tcLeft += pixelW
+ tcRight -= pixelW
+
+ tcBottom += pixelH
+ tcTop -= pixelH
+
+ tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+ }
+ }
+ }
+ }
+
+ fun drawTile(tile: Int, x: Float, y: Float) {
+ tiles[tile].render(x, y)
+ }
+
+ fun drawLayer(layerIndex: Int, xo: Float, yo: Float) {
+ var x = 0f
+ var y = 0f
+ val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)")
+ val layer = layers[layerIndex]
+
+ val layerData = layer.data
+ if (layerData != null) {
+ for (index in layerData.indices) {
+ // todo: determine if in view
+ // todo: determine tilewidth
+ //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) {
+ drawTile(layerData[index], xo + x * 128f, yo + y * 128f)
+
+ when (data.renderorder) {
+ "right-down" -> {
+ x++
+ if (x >= layer.width) {
+ x = 0f
+ y--
+ }
+ }
+ else -> {
+ throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this")
+ }
+ }
+ //}
+ }
+ }
+
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
+
+ tx.render()
+ }
+ }
+ }
+
+
+ first = false
+ }
+}
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/settings.gradle b/settings.gradle
index 329f712..3181c92 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-rootProject.name = 'kotlin-webgl-test'
+rootProject.name = 'kudens'
diff --git a/src/com/persesgames/game/Game.kt b/src/com/persesgames/game/Game.kt
new file mode 100644
index 0000000..3abdd56
--- /dev/null
+++ b/src/com/persesgames/game/Game.kt
@@ -0,0 +1,155 @@
+package com.persesgames.game
+
+import com.persesgames.texture.Textures
+import org.khronos.webgl.WebGLRenderingContext
+import org.w3c.dom.CanvasRenderingContext2D
+import org.w3c.dom.HTMLCanvasElement
+import org.w3c.dom.HTMLElement
+import kotlin.browser.document
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+enum class DrawMode {
+ LINEAR,
+ NEAREST
+}
+
+class HTMLElements {
+ var container: HTMLElement
+ var webgl: WebGLRenderingContext
+ var canvas2d: CanvasRenderingContext2D
+
+ init {
+ container = document.createElement("div") as HTMLElement
+
+ val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement
+ val canvas = document.createElement("canvas") as HTMLCanvasElement
+
+ container.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
+ webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" )
+ canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" )
+
+ document.body!!.appendChild(container)
+ container.appendChild(webGlCanvas)
+ container.appendChild(canvas)
+
+ webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext
+ canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D
+ }
+}
+
+object Game {
+ var started = false
+ val view: View = View()
+ val html: HTMLElements by lazy { HTMLElements() }
+ var currentScreen: Screen = DefaultScreen()
+ var start = Date().getTime()
+ var currentTime = start
+ var currentDelta = 0f
+ var pause: Boolean = false
+
+ var fps = 0
+ var fpsCount = 0
+ var fpsCountTime = 0f
+
+ fun gl() = html.webgl
+
+ fun resize() {
+ val canvas = gl().canvas
+
+ // Check if the canvas is not the same size.
+ val windowWidth = window.innerWidth.toInt()
+ val windowHeight = window.innerHeight.toInt()
+
+ if (view.lastWindowWidth != windowWidth ||
+ view.lastWindowHeight != windowHeight) {
+ view.lastWindowWidth = windowWidth
+ view.lastWindowHeight = windowHeight
+ view.windowWidth = windowWidth
+ view.windowHeight = windowHeight
+
+ view.updateView()
+
+ val textCanvas = html.canvas2d.canvas
+
+ // Make the canvas the same size
+ canvas.width = view.width.toInt()
+ canvas.height = view.height.toInt()
+
+ textCanvas.width = view.width.toInt()
+ textCanvas.height = view.height.toInt()
+
+ gl().viewport(0, 0, view.width.toInt(), view.height.toInt())
+
+ val left = (windowWidth - view.windowWidth) / 2
+ val top = (windowHeight - view.windowHeight) / 2
+
+ canvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ textCanvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ }
+ }
+
+ fun start(startScreen: Screen) {
+ if (started) {
+ throw IllegalStateException("You can only start a game once!")
+ }
+
+ setScreen(startScreen)
+
+ // start game loop
+ started = true
+ gameLoop()
+ }
+
+ fun setScreen(screen: Screen) {
+ currentScreen.closeResources()
+
+ currentScreen = screen
+
+ currentScreen.loadResources()
+ }
+
+ fun gameLoop() {
+ if (!Textures.ready()) {
+ Game.gl().clearColor(1f, 1f, 1f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ } else {
+ resize()
+
+ if (!pause) {
+ html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble());
+
+ Game.gl().clearColor(0f, 0f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+
+ Game.gl().enable(WebGLRenderingContext.BLEND);
+ Game.gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA); //ONE_MINUS_DST_ALPHA);
+
+ val time = Date().getTime()
+ currentDelta = (time - currentTime) / 1000f
+ currentTime = time
+
+ val timeInSeconds = (currentTime - start) / 1000f
+
+ fpsCountTime += currentDelta
+ fpsCount++
+ while (fpsCountTime > 1f) {
+ fps = fpsCount
+ fpsCountTime -= 1f
+ fpsCount = 0
+ }
+
+ currentScreen.update(timeInSeconds, currentDelta);
+ currentScreen.render()
+ }
+ }
+
+ window.requestAnimationFrame {
+ gameLoop()
+ }
+ }
+
+}
diff --git a/src/com/persesgames/game/Screen.kt b/src/com/persesgames/game/Screen.kt
new file mode 100644
index 0000000..6fb558e
--- /dev/null
+++ b/src/com/persesgames/game/Screen.kt
@@ -0,0 +1,35 @@
+package com.persesgames.game
+
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+abstract class Screen {
+
+ open fun loadResources() {
+
+ }
+
+ open fun closeResources() {
+
+ }
+
+ abstract fun update(time: Float, delta: Float)
+
+ abstract fun render()
+
+}
+
+
+class DefaultScreen: Screen() {
+ override fun update(time: Float, delta: Float) {
+ }
+
+ override fun render() {
+ // show loading message?
+ Game.gl().clearColor(1f, 1f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/game/View.kt b/src/com/persesgames/game/View.kt
new file mode 100644
index 0000000..e5590e0
--- /dev/null
+++ b/src/com/persesgames/game/View.kt
@@ -0,0 +1,221 @@
+package com.persesgames.game
+
+import com.persesgames.math.Matrix4
+
+enum class ViewType {
+ PROJECTION,
+ WIDTH,
+ HEIGHT,
+ ABSOLUTE
+}
+
+class View(
+ var lastWindowWidth: Int = 2000,
+ var lastWindowHeight: Int = 1000,
+ var windowWidth: Int = 2000,
+ var windowHeight: Int = 1000,
+ var width: Float = 1024f,
+ var height: Float = 1024f,
+ var angle: Float = 60f,
+ var near: Float = -0.1f,
+ var far: Float = -100f,
+ var minAspectRatio: Float = 1f,
+ var maxAspectRatio: Float = 1f,
+ var leftOffset: Int = 0,
+ var bottomOffset: Int = 0,
+ var viewType: ViewType = ViewType.WIDTH,
+ var drawMode: DrawMode = DrawMode.LINEAR) {
+ var vMatrix = Matrix4()
+ var aspectRatio = 1f
+
+ init {
+ updateView()
+ }
+
+ fun requestFullscreen() {
+ println("Requesting fullscreen")
+ js("""
+ if (document.webkitFullscreenElement) {
+ document.webkitCancelFullScreen();
+ } else {
+ document.documentElement.webkitRequestFullScreen();
+ }
+ """)
+ //if (document.fullscreenEnabled) {
+ // println("fullscreen Enabled")
+ //Game.html.container.requestFullscreen()
+ //document.documentElement?.requestFullscreen()
+ //}
+ }
+
+ fun updateView() {
+ aspectRatio = windowWidth / windowHeight.toFloat()
+
+ if (aspectRatio < minAspectRatio) {
+ aspectRatio = minAspectRatio
+
+ windowHeight = (windowWidth / aspectRatio).toInt()
+ }
+
+ if (aspectRatio > maxAspectRatio) {
+ aspectRatio = maxAspectRatio
+
+ windowWidth = (windowHeight * aspectRatio).toInt()
+ }
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.WIDTH -> {
+ height = width / aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.HEIGHT -> {
+ width = height * aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.PROJECTION -> {
+ vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far);
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ //println("width: $width, height: $height")
+ }
+
+ fun screenToGameCoordX(screenX: Float): Float {
+ var result = screenX
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.HEIGHT -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun screenToGameCoordY(screenY: Float): Float {
+ var result = screenY
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.HEIGHT -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordX(gameX: Float): Float {
+ var result = gameX
+ val normalizedX = gameX + (width / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.HEIGHT -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordY(gameY: Float): Float {
+ var result = gameY
+ val normalizedY = gameY + (height / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.HEIGHT -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun setToWidth(width: Float) {
+ this.width = width
+ this.viewType = ViewType.WIDTH
+
+ updateView()
+ }
+
+ fun setToHeight(height: Float) {
+ this.height = height
+ this.viewType = ViewType.HEIGHT
+
+ updateView()
+ }
+
+ fun setProjection(angle: Float) {
+ this.angle = angle
+ this.viewType = ViewType.PROJECTION
+
+ updateView()
+ }
+
+ fun setNear(near: Float) {
+ this.near = near
+
+ updateView()
+ }
+
+ fun setFar(far: Float) {
+ this.far = far
+
+ updateView()
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/input/Keys.kt b/src/com/persesgames/input/Keys.kt
new file mode 100644
index 0000000..6705c67
--- /dev/null
+++ b/src/com/persesgames/input/Keys.kt
@@ -0,0 +1,141 @@
+package com.persesgames.input
+
+import com.persesgames.game.Game
+import org.w3c.dom.events.Event
+import org.w3c.dom.events.KeyboardEvent
+import org.w3c.dom.events.MouseEvent
+import java.util.*
+import kotlin.browser.document
+import kotlin.dom.on
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 12:18
+ */
+
+enum class KeyCode(val keyCode: Int) {
+ LEFT(37),
+ UP(38),
+ DOWN(40),
+ RIGHT(39),
+ SPACE(32),
+ MINUS(109),
+ PLUS(107),
+}
+
+interface InputProcessor {
+
+ fun keyPressed(charCode: Int)
+
+ fun keyDown(keyCode: Int)
+
+ fun keyUp(keyCode: Int)
+
+ fun pointerClick(pointer: Int, x: Float, y: Float)
+
+}
+
+open class EmptyInputProcessor : InputProcessor {
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ }
+
+ override fun keyDown(keyCode: Int) {
+ }
+
+ override fun keyPressed(charCode: Int) {
+ }
+
+ override fun keyUp(keyCode: Int) {
+ }
+
+
+}
+
+object Keys {
+
+ private val keys: MutableMap = HashMap();
+ private var inputProcesser: InputProcessor = EmptyInputProcessor()
+
+ init {
+ val body = document.body
+ if (body != null) {
+ body.on("keydown", true) {
+ Keys.keyDown(it)
+ }
+
+ body.on("keyup", true) {
+ Keys.keyUp(it)
+ }
+
+ body.on("keypress", true) {
+ Keys.keyPress(it)
+ }
+
+ body.on("click", true) {
+ Keys.mouseClick(it)
+ }
+
+ body.on("mousedown", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mouseup", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mousemove", true) {
+ Keys.mouseMove(it)
+ }
+ }
+ }
+
+ fun setInputProcessor(processor: InputProcessor) {
+ this.inputProcesser = processor
+ }
+
+ private fun keyDown(key: Event) {
+ if (key is KeyboardEvent) {
+ keys.put(key.keyCode, Date().getTime())
+
+ inputProcesser.keyDown(key.keyCode)
+ }
+ }
+
+ private fun keyUp(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyUp(key.keyCode)
+
+ keys.remove(key.keyCode)
+ }
+ }
+
+ private fun keyPress(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyPressed(key.charCode)
+ }
+ }
+
+ private fun mouseClick(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+ inputProcesser.pointerClick(event.button.toInt(), vx, vy)
+ }
+ }
+
+ private fun mouseMove(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+
+ }
+ }
+
+ fun isDown(keyCode: Int) = keys.containsKey(keyCode)
+
+ fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode)
+
+}
diff --git a/src/com/persesgames/map/Map.kt b/src/com/persesgames/map/Map.kt
new file mode 100644
index 0000000..b5d7bc8
--- /dev/null
+++ b/src/com/persesgames/map/Map.kt
@@ -0,0 +1,9 @@
+package com.persesgames.map
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+open class Map {
+
+}
diff --git a/src/com/persesgames/map/tiled/TiledMap.kt b/src/com/persesgames/map/tiled/TiledMap.kt
new file mode 100644
index 0000000..a84a5a3
--- /dev/null
+++ b/src/com/persesgames/map/tiled/TiledMap.kt
@@ -0,0 +1,211 @@
+package com.persesgames.map.tiled
+
+import com.persesgames.net.getUrlAsString
+import com.persesgames.texture.Texture
+import com.persesgames.texture.Textures
+import java.util.*
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+class MapData {
+ var version: Int = 1
+ var properties: MutableMap = HashMap()
+ var layers: Array? = null
+ var tilesets: Array? = null
+
+ var height: Int = 0
+ var width: Int = 0
+
+ var nextobjectid: Int = 0
+ var orientation: String = "orthogonal"
+ var renderorder: String = "right-down"
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+}
+
+class MapLayer {
+ var properties: MutableMap = HashMap()
+
+ var data: Array? = null
+ var encoding: String = ""
+ var x: Int = 0
+ var y: Int = 0
+ var width: Int = 0
+ var height: Int = 0
+ var name: String = ""
+ var opacity: Float = 1f
+ var type: String = ""
+ var visible: Boolean = true
+ var draworder: String = ""
+}
+
+class MapTileset {
+ var properties: MutableMap = HashMap()
+
+ var firstgid: Int = 0
+ var image: String = ""
+ var imageheight: Int = 0
+ var imagewidth: Int = 0
+ var margin: Int = 0
+ var name: String = ""
+ var spacing: Int = 0
+ var tilecount: Int = 0
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+ var tileproperties: MutableMap> = HashMap()
+}
+
+class TilesetIndex(
+ val texture: Texture?,
+ val tcLeft: Float,
+ val tcTop: Float,
+ val tcRight: Float,
+ val tcBottom: Float,
+ val scale: Float
+ ) {
+ constructor() : this(null, 0f, 0f, 0f, 0f, 0f)
+
+ fun render(x: Float, y: Float) {
+ texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+}
+
+class TiledMap(dir: String = "", url: String) {
+ val properties: Map = HashMap()
+ val data: MapData
+ val tileset: Array
+ val tiles: Array
+ var first = true
+ //var tilesetIndex: Array = Array(0, { TilesetIndex() })
+
+ init {
+ var tileDir = dir
+ if (!tileDir.isEmpty() && !tileDir.endsWith("/")) {
+ tileDir = tileDir + "/"
+ }
+
+ data = JSON.parse(getUrlAsString(tileDir + url))
+ println("map data is loaded")
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ tileset = Array(tilesets.size, { "" })
+ var maxGid = 0
+ for (index in 0..tilesets.size - 1) {
+ tileset[index] = tilesets[index].name
+ Textures.load(tilesets[index].name, tileDir + tilesets[index].image)
+ maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount)
+ }
+
+ tiles = Array(maxGid, { TilesetIndex() })
+ } else {
+ tileset = Array(0, { "" })
+ tiles = Array(0, { TilesetIndex() })
+ }
+
+ cacheTiles()
+ }
+
+ fun cacheTiles() {
+ if (!Textures.ready()) {
+ window.setTimeout({ cacheTiles() }, 10)
+ } else {
+ val tilesets = data.tilesets
+ var tcLeft = 0f
+ var tcTop = 0f
+ var tcRight = 0f
+ var tcBottom = 0f
+
+ if (tilesets != null) {
+
+
+ for (tileset in tilesets) {
+ val tilesHor = tileset.imagewidth / tileset.tilewidth
+ val tilesVer = tileset.imageheight / tileset.tileheight
+ val scale = (tileset.tilewidth / tileset.imagewidth.toFloat())
+
+ for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) {
+ val texture = Textures.get(tileset.name)
+
+ val gid = index - tileset.firstgid
+
+ val xi = gid % tilesHor
+ var yi = gid / tilesHor
+ yi = tilesVer - yi - 1
+ val tw = 1f / tilesHor.toFloat()
+ val th = 1f / tilesVer.toFloat()
+
+ val pixelW = 0.1f / tileset.tilewidth
+ val pixelH = 0.1f / tileset.tileheight
+
+ tcLeft = xi * tw
+ tcRight = tcLeft + tw
+
+ // switch up/down because of texture coord 0,0 in left bottom corner
+ tcBottom = yi * th
+ tcTop = tcBottom + th
+
+ tcLeft += pixelW
+ tcRight -= pixelW
+
+ tcBottom += pixelH
+ tcTop -= pixelH
+
+ tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+ }
+ }
+ }
+ }
+
+ fun drawTile(tile: Int, x: Float, y: Float) {
+ tiles[tile].render(x, y)
+ }
+
+ fun drawLayer(layerIndex: Int, xo: Float, yo: Float) {
+ var x = 0f
+ var y = 0f
+ val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)")
+ val layer = layers[layerIndex]
+
+ val layerData = layer.data
+ if (layerData != null) {
+ for (index in layerData.indices) {
+ // todo: determine if in view
+ // todo: determine tilewidth
+ //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) {
+ drawTile(layerData[index], xo + x * 128f, yo + y * 128f)
+
+ when (data.renderorder) {
+ "right-down" -> {
+ x++
+ if (x >= layer.width) {
+ x = 0f
+ y--
+ }
+ }
+ else -> {
+ throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this")
+ }
+ }
+ //}
+ }
+ }
+
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
+
+ tx.render()
+ }
+ }
+ }
+
+
+ first = false
+ }
+}
diff --git a/src/com/persesgames/math/Matrix4.kt b/src/com/persesgames/math/Matrix4.kt
new file mode 100644
index 0000000..3cb4ed4
--- /dev/null
+++ b/src/com/persesgames/math/Matrix4.kt
@@ -0,0 +1,192 @@
+package com.persesgames.math
+
+import org.khronos.webgl.Float32Array
+
+/**
+ * User: rnentjes
+ * Date: 17-4-16
+ * Time: 15:43
+ */
+class Matrix4 {
+
+ internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ internal var temp = FloatArray(16)
+
+ private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ fun get(): FloatArray {
+ return matrix
+ }
+
+ fun getFloat32Array() = Float32Array(get().toTypedArray())
+
+ fun set(values: FloatArray) {
+ if (values.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ matrix = values
+ }
+
+ fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) {
+ val r = (angle / 180f * Math.PI).toFloat()
+ val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat()
+
+ matrix[0] = f / imageAspectRatio
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+
+ matrix[4] = 0.0f
+ matrix[5] = f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = -(far + near) / (far - near)
+ matrix[11] = -1.0f
+
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = -(2.0f * far * near) / (far - near)
+ matrix[15] = 0.0f
+ }
+
+ fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) {
+ matrix[0] = 2f / (right - left)
+ matrix[1] = 0f
+ matrix[2] = 0f
+ matrix[3] = 0f
+
+ matrix[4] = 0f
+ matrix[5] = 2f / (top - bottom)
+ matrix[6] = 0f
+ matrix[7] = 0f
+
+ matrix[8] = 0f
+ matrix[9] = 0f
+ matrix[10] = -2f / (far - near)
+ matrix[11] = 0f
+
+ matrix[12] = - (right + left) / (right - left)
+ matrix[13] = - (top + bottom) / (top - bottom)
+ matrix[14] = - (far + near) / (far - near)
+ matrix[15] = 1f
+ }
+
+ fun setToIdentity() {
+ matrix[0] = 1.0f
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+ matrix[4] = 0.0f
+ matrix[5] = 1.0f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = 1.0f
+ matrix[11] = 0.0f
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = 0.0f
+ matrix[15] = 1.0f
+ }
+
+ fun mul(other: Matrix4) {
+ mul(other.get())
+ }
+
+ protected fun mul(other: FloatArray) {
+ if (other.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12]
+ temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13]
+ temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14]
+ temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15]
+ temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12]
+ temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13]
+ temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14]
+ temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15]
+ temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12]
+ temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13]
+ temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14]
+ temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15]
+ temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12]
+ temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13]
+ temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14]
+ temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15]
+
+ matrix[0] = temp[0]
+ matrix[1] = temp[1]
+ matrix[2] = temp[2]
+ matrix[3] = temp[3]
+ matrix[4] = temp[4]
+ matrix[5] = temp[5]
+ matrix[6] = temp[6]
+ matrix[7] = temp[7]
+ matrix[8] = temp[8]
+ matrix[9] = temp[9]
+ matrix[10] = temp[10]
+ matrix[11] = temp[11]
+ matrix[12] = temp[12]
+ matrix[13] = temp[13]
+ matrix[14] = temp[14]
+ matrix[15] = temp[15]
+ }
+
+ fun translate(x: Float, y: Float, z: Float) {
+ translateMatrix[12] = x
+ translateMatrix[13] = y
+ translateMatrix[14] = z
+
+ mul(translateMatrix)
+ }
+
+ fun scale(x: Float, y: Float, z: Float) {
+ scaleMatrix[0] = x
+ scaleMatrix[5] = y
+ scaleMatrix[10] = z
+
+ mul(scaleMatrix)
+ }
+
+ fun rotateX(angle: Float) {
+ rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+ rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat()
+ rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateXMatrix)
+ }
+
+ fun rotateY(angle: Float) {
+ rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat()
+ rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateYMatrix)
+ }
+
+ fun rotateZ(angle: Float) {
+ rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat()
+ rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateZMatrix)
+ }
+}
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/settings.gradle b/settings.gradle
index 329f712..3181c92 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-rootProject.name = 'kotlin-webgl-test'
+rootProject.name = 'kudens'
diff --git a/src/com/persesgames/game/Game.kt b/src/com/persesgames/game/Game.kt
new file mode 100644
index 0000000..3abdd56
--- /dev/null
+++ b/src/com/persesgames/game/Game.kt
@@ -0,0 +1,155 @@
+package com.persesgames.game
+
+import com.persesgames.texture.Textures
+import org.khronos.webgl.WebGLRenderingContext
+import org.w3c.dom.CanvasRenderingContext2D
+import org.w3c.dom.HTMLCanvasElement
+import org.w3c.dom.HTMLElement
+import kotlin.browser.document
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+enum class DrawMode {
+ LINEAR,
+ NEAREST
+}
+
+class HTMLElements {
+ var container: HTMLElement
+ var webgl: WebGLRenderingContext
+ var canvas2d: CanvasRenderingContext2D
+
+ init {
+ container = document.createElement("div") as HTMLElement
+
+ val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement
+ val canvas = document.createElement("canvas") as HTMLCanvasElement
+
+ container.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
+ webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" )
+ canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" )
+
+ document.body!!.appendChild(container)
+ container.appendChild(webGlCanvas)
+ container.appendChild(canvas)
+
+ webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext
+ canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D
+ }
+}
+
+object Game {
+ var started = false
+ val view: View = View()
+ val html: HTMLElements by lazy { HTMLElements() }
+ var currentScreen: Screen = DefaultScreen()
+ var start = Date().getTime()
+ var currentTime = start
+ var currentDelta = 0f
+ var pause: Boolean = false
+
+ var fps = 0
+ var fpsCount = 0
+ var fpsCountTime = 0f
+
+ fun gl() = html.webgl
+
+ fun resize() {
+ val canvas = gl().canvas
+
+ // Check if the canvas is not the same size.
+ val windowWidth = window.innerWidth.toInt()
+ val windowHeight = window.innerHeight.toInt()
+
+ if (view.lastWindowWidth != windowWidth ||
+ view.lastWindowHeight != windowHeight) {
+ view.lastWindowWidth = windowWidth
+ view.lastWindowHeight = windowHeight
+ view.windowWidth = windowWidth
+ view.windowHeight = windowHeight
+
+ view.updateView()
+
+ val textCanvas = html.canvas2d.canvas
+
+ // Make the canvas the same size
+ canvas.width = view.width.toInt()
+ canvas.height = view.height.toInt()
+
+ textCanvas.width = view.width.toInt()
+ textCanvas.height = view.height.toInt()
+
+ gl().viewport(0, 0, view.width.toInt(), view.height.toInt())
+
+ val left = (windowWidth - view.windowWidth) / 2
+ val top = (windowHeight - view.windowHeight) / 2
+
+ canvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ textCanvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ }
+ }
+
+ fun start(startScreen: Screen) {
+ if (started) {
+ throw IllegalStateException("You can only start a game once!")
+ }
+
+ setScreen(startScreen)
+
+ // start game loop
+ started = true
+ gameLoop()
+ }
+
+ fun setScreen(screen: Screen) {
+ currentScreen.closeResources()
+
+ currentScreen = screen
+
+ currentScreen.loadResources()
+ }
+
+ fun gameLoop() {
+ if (!Textures.ready()) {
+ Game.gl().clearColor(1f, 1f, 1f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ } else {
+ resize()
+
+ if (!pause) {
+ html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble());
+
+ Game.gl().clearColor(0f, 0f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+
+ Game.gl().enable(WebGLRenderingContext.BLEND);
+ Game.gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA); //ONE_MINUS_DST_ALPHA);
+
+ val time = Date().getTime()
+ currentDelta = (time - currentTime) / 1000f
+ currentTime = time
+
+ val timeInSeconds = (currentTime - start) / 1000f
+
+ fpsCountTime += currentDelta
+ fpsCount++
+ while (fpsCountTime > 1f) {
+ fps = fpsCount
+ fpsCountTime -= 1f
+ fpsCount = 0
+ }
+
+ currentScreen.update(timeInSeconds, currentDelta);
+ currentScreen.render()
+ }
+ }
+
+ window.requestAnimationFrame {
+ gameLoop()
+ }
+ }
+
+}
diff --git a/src/com/persesgames/game/Screen.kt b/src/com/persesgames/game/Screen.kt
new file mode 100644
index 0000000..6fb558e
--- /dev/null
+++ b/src/com/persesgames/game/Screen.kt
@@ -0,0 +1,35 @@
+package com.persesgames.game
+
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+abstract class Screen {
+
+ open fun loadResources() {
+
+ }
+
+ open fun closeResources() {
+
+ }
+
+ abstract fun update(time: Float, delta: Float)
+
+ abstract fun render()
+
+}
+
+
+class DefaultScreen: Screen() {
+ override fun update(time: Float, delta: Float) {
+ }
+
+ override fun render() {
+ // show loading message?
+ Game.gl().clearColor(1f, 1f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/game/View.kt b/src/com/persesgames/game/View.kt
new file mode 100644
index 0000000..e5590e0
--- /dev/null
+++ b/src/com/persesgames/game/View.kt
@@ -0,0 +1,221 @@
+package com.persesgames.game
+
+import com.persesgames.math.Matrix4
+
+enum class ViewType {
+ PROJECTION,
+ WIDTH,
+ HEIGHT,
+ ABSOLUTE
+}
+
+class View(
+ var lastWindowWidth: Int = 2000,
+ var lastWindowHeight: Int = 1000,
+ var windowWidth: Int = 2000,
+ var windowHeight: Int = 1000,
+ var width: Float = 1024f,
+ var height: Float = 1024f,
+ var angle: Float = 60f,
+ var near: Float = -0.1f,
+ var far: Float = -100f,
+ var minAspectRatio: Float = 1f,
+ var maxAspectRatio: Float = 1f,
+ var leftOffset: Int = 0,
+ var bottomOffset: Int = 0,
+ var viewType: ViewType = ViewType.WIDTH,
+ var drawMode: DrawMode = DrawMode.LINEAR) {
+ var vMatrix = Matrix4()
+ var aspectRatio = 1f
+
+ init {
+ updateView()
+ }
+
+ fun requestFullscreen() {
+ println("Requesting fullscreen")
+ js("""
+ if (document.webkitFullscreenElement) {
+ document.webkitCancelFullScreen();
+ } else {
+ document.documentElement.webkitRequestFullScreen();
+ }
+ """)
+ //if (document.fullscreenEnabled) {
+ // println("fullscreen Enabled")
+ //Game.html.container.requestFullscreen()
+ //document.documentElement?.requestFullscreen()
+ //}
+ }
+
+ fun updateView() {
+ aspectRatio = windowWidth / windowHeight.toFloat()
+
+ if (aspectRatio < minAspectRatio) {
+ aspectRatio = minAspectRatio
+
+ windowHeight = (windowWidth / aspectRatio).toInt()
+ }
+
+ if (aspectRatio > maxAspectRatio) {
+ aspectRatio = maxAspectRatio
+
+ windowWidth = (windowHeight * aspectRatio).toInt()
+ }
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.WIDTH -> {
+ height = width / aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.HEIGHT -> {
+ width = height * aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.PROJECTION -> {
+ vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far);
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ //println("width: $width, height: $height")
+ }
+
+ fun screenToGameCoordX(screenX: Float): Float {
+ var result = screenX
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.HEIGHT -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun screenToGameCoordY(screenY: Float): Float {
+ var result = screenY
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.HEIGHT -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordX(gameX: Float): Float {
+ var result = gameX
+ val normalizedX = gameX + (width / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.HEIGHT -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordY(gameY: Float): Float {
+ var result = gameY
+ val normalizedY = gameY + (height / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.HEIGHT -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun setToWidth(width: Float) {
+ this.width = width
+ this.viewType = ViewType.WIDTH
+
+ updateView()
+ }
+
+ fun setToHeight(height: Float) {
+ this.height = height
+ this.viewType = ViewType.HEIGHT
+
+ updateView()
+ }
+
+ fun setProjection(angle: Float) {
+ this.angle = angle
+ this.viewType = ViewType.PROJECTION
+
+ updateView()
+ }
+
+ fun setNear(near: Float) {
+ this.near = near
+
+ updateView()
+ }
+
+ fun setFar(far: Float) {
+ this.far = far
+
+ updateView()
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/input/Keys.kt b/src/com/persesgames/input/Keys.kt
new file mode 100644
index 0000000..6705c67
--- /dev/null
+++ b/src/com/persesgames/input/Keys.kt
@@ -0,0 +1,141 @@
+package com.persesgames.input
+
+import com.persesgames.game.Game
+import org.w3c.dom.events.Event
+import org.w3c.dom.events.KeyboardEvent
+import org.w3c.dom.events.MouseEvent
+import java.util.*
+import kotlin.browser.document
+import kotlin.dom.on
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 12:18
+ */
+
+enum class KeyCode(val keyCode: Int) {
+ LEFT(37),
+ UP(38),
+ DOWN(40),
+ RIGHT(39),
+ SPACE(32),
+ MINUS(109),
+ PLUS(107),
+}
+
+interface InputProcessor {
+
+ fun keyPressed(charCode: Int)
+
+ fun keyDown(keyCode: Int)
+
+ fun keyUp(keyCode: Int)
+
+ fun pointerClick(pointer: Int, x: Float, y: Float)
+
+}
+
+open class EmptyInputProcessor : InputProcessor {
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ }
+
+ override fun keyDown(keyCode: Int) {
+ }
+
+ override fun keyPressed(charCode: Int) {
+ }
+
+ override fun keyUp(keyCode: Int) {
+ }
+
+
+}
+
+object Keys {
+
+ private val keys: MutableMap = HashMap();
+ private var inputProcesser: InputProcessor = EmptyInputProcessor()
+
+ init {
+ val body = document.body
+ if (body != null) {
+ body.on("keydown", true) {
+ Keys.keyDown(it)
+ }
+
+ body.on("keyup", true) {
+ Keys.keyUp(it)
+ }
+
+ body.on("keypress", true) {
+ Keys.keyPress(it)
+ }
+
+ body.on("click", true) {
+ Keys.mouseClick(it)
+ }
+
+ body.on("mousedown", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mouseup", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mousemove", true) {
+ Keys.mouseMove(it)
+ }
+ }
+ }
+
+ fun setInputProcessor(processor: InputProcessor) {
+ this.inputProcesser = processor
+ }
+
+ private fun keyDown(key: Event) {
+ if (key is KeyboardEvent) {
+ keys.put(key.keyCode, Date().getTime())
+
+ inputProcesser.keyDown(key.keyCode)
+ }
+ }
+
+ private fun keyUp(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyUp(key.keyCode)
+
+ keys.remove(key.keyCode)
+ }
+ }
+
+ private fun keyPress(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyPressed(key.charCode)
+ }
+ }
+
+ private fun mouseClick(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+ inputProcesser.pointerClick(event.button.toInt(), vx, vy)
+ }
+ }
+
+ private fun mouseMove(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+
+ }
+ }
+
+ fun isDown(keyCode: Int) = keys.containsKey(keyCode)
+
+ fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode)
+
+}
diff --git a/src/com/persesgames/map/Map.kt b/src/com/persesgames/map/Map.kt
new file mode 100644
index 0000000..b5d7bc8
--- /dev/null
+++ b/src/com/persesgames/map/Map.kt
@@ -0,0 +1,9 @@
+package com.persesgames.map
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+open class Map {
+
+}
diff --git a/src/com/persesgames/map/tiled/TiledMap.kt b/src/com/persesgames/map/tiled/TiledMap.kt
new file mode 100644
index 0000000..a84a5a3
--- /dev/null
+++ b/src/com/persesgames/map/tiled/TiledMap.kt
@@ -0,0 +1,211 @@
+package com.persesgames.map.tiled
+
+import com.persesgames.net.getUrlAsString
+import com.persesgames.texture.Texture
+import com.persesgames.texture.Textures
+import java.util.*
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+class MapData {
+ var version: Int = 1
+ var properties: MutableMap = HashMap()
+ var layers: Array? = null
+ var tilesets: Array? = null
+
+ var height: Int = 0
+ var width: Int = 0
+
+ var nextobjectid: Int = 0
+ var orientation: String = "orthogonal"
+ var renderorder: String = "right-down"
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+}
+
+class MapLayer {
+ var properties: MutableMap = HashMap()
+
+ var data: Array? = null
+ var encoding: String = ""
+ var x: Int = 0
+ var y: Int = 0
+ var width: Int = 0
+ var height: Int = 0
+ var name: String = ""
+ var opacity: Float = 1f
+ var type: String = ""
+ var visible: Boolean = true
+ var draworder: String = ""
+}
+
+class MapTileset {
+ var properties: MutableMap = HashMap()
+
+ var firstgid: Int = 0
+ var image: String = ""
+ var imageheight: Int = 0
+ var imagewidth: Int = 0
+ var margin: Int = 0
+ var name: String = ""
+ var spacing: Int = 0
+ var tilecount: Int = 0
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+ var tileproperties: MutableMap> = HashMap()
+}
+
+class TilesetIndex(
+ val texture: Texture?,
+ val tcLeft: Float,
+ val tcTop: Float,
+ val tcRight: Float,
+ val tcBottom: Float,
+ val scale: Float
+ ) {
+ constructor() : this(null, 0f, 0f, 0f, 0f, 0f)
+
+ fun render(x: Float, y: Float) {
+ texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+}
+
+class TiledMap(dir: String = "", url: String) {
+ val properties: Map = HashMap()
+ val data: MapData
+ val tileset: Array
+ val tiles: Array
+ var first = true
+ //var tilesetIndex: Array = Array(0, { TilesetIndex() })
+
+ init {
+ var tileDir = dir
+ if (!tileDir.isEmpty() && !tileDir.endsWith("/")) {
+ tileDir = tileDir + "/"
+ }
+
+ data = JSON.parse(getUrlAsString(tileDir + url))
+ println("map data is loaded")
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ tileset = Array(tilesets.size, { "" })
+ var maxGid = 0
+ for (index in 0..tilesets.size - 1) {
+ tileset[index] = tilesets[index].name
+ Textures.load(tilesets[index].name, tileDir + tilesets[index].image)
+ maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount)
+ }
+
+ tiles = Array(maxGid, { TilesetIndex() })
+ } else {
+ tileset = Array(0, { "" })
+ tiles = Array(0, { TilesetIndex() })
+ }
+
+ cacheTiles()
+ }
+
+ fun cacheTiles() {
+ if (!Textures.ready()) {
+ window.setTimeout({ cacheTiles() }, 10)
+ } else {
+ val tilesets = data.tilesets
+ var tcLeft = 0f
+ var tcTop = 0f
+ var tcRight = 0f
+ var tcBottom = 0f
+
+ if (tilesets != null) {
+
+
+ for (tileset in tilesets) {
+ val tilesHor = tileset.imagewidth / tileset.tilewidth
+ val tilesVer = tileset.imageheight / tileset.tileheight
+ val scale = (tileset.tilewidth / tileset.imagewidth.toFloat())
+
+ for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) {
+ val texture = Textures.get(tileset.name)
+
+ val gid = index - tileset.firstgid
+
+ val xi = gid % tilesHor
+ var yi = gid / tilesHor
+ yi = tilesVer - yi - 1
+ val tw = 1f / tilesHor.toFloat()
+ val th = 1f / tilesVer.toFloat()
+
+ val pixelW = 0.1f / tileset.tilewidth
+ val pixelH = 0.1f / tileset.tileheight
+
+ tcLeft = xi * tw
+ tcRight = tcLeft + tw
+
+ // switch up/down because of texture coord 0,0 in left bottom corner
+ tcBottom = yi * th
+ tcTop = tcBottom + th
+
+ tcLeft += pixelW
+ tcRight -= pixelW
+
+ tcBottom += pixelH
+ tcTop -= pixelH
+
+ tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+ }
+ }
+ }
+ }
+
+ fun drawTile(tile: Int, x: Float, y: Float) {
+ tiles[tile].render(x, y)
+ }
+
+ fun drawLayer(layerIndex: Int, xo: Float, yo: Float) {
+ var x = 0f
+ var y = 0f
+ val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)")
+ val layer = layers[layerIndex]
+
+ val layerData = layer.data
+ if (layerData != null) {
+ for (index in layerData.indices) {
+ // todo: determine if in view
+ // todo: determine tilewidth
+ //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) {
+ drawTile(layerData[index], xo + x * 128f, yo + y * 128f)
+
+ when (data.renderorder) {
+ "right-down" -> {
+ x++
+ if (x >= layer.width) {
+ x = 0f
+ y--
+ }
+ }
+ else -> {
+ throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this")
+ }
+ }
+ //}
+ }
+ }
+
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
+
+ tx.render()
+ }
+ }
+ }
+
+
+ first = false
+ }
+}
diff --git a/src/com/persesgames/math/Matrix4.kt b/src/com/persesgames/math/Matrix4.kt
new file mode 100644
index 0000000..3cb4ed4
--- /dev/null
+++ b/src/com/persesgames/math/Matrix4.kt
@@ -0,0 +1,192 @@
+package com.persesgames.math
+
+import org.khronos.webgl.Float32Array
+
+/**
+ * User: rnentjes
+ * Date: 17-4-16
+ * Time: 15:43
+ */
+class Matrix4 {
+
+ internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ internal var temp = FloatArray(16)
+
+ private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ fun get(): FloatArray {
+ return matrix
+ }
+
+ fun getFloat32Array() = Float32Array(get().toTypedArray())
+
+ fun set(values: FloatArray) {
+ if (values.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ matrix = values
+ }
+
+ fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) {
+ val r = (angle / 180f * Math.PI).toFloat()
+ val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat()
+
+ matrix[0] = f / imageAspectRatio
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+
+ matrix[4] = 0.0f
+ matrix[5] = f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = -(far + near) / (far - near)
+ matrix[11] = -1.0f
+
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = -(2.0f * far * near) / (far - near)
+ matrix[15] = 0.0f
+ }
+
+ fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) {
+ matrix[0] = 2f / (right - left)
+ matrix[1] = 0f
+ matrix[2] = 0f
+ matrix[3] = 0f
+
+ matrix[4] = 0f
+ matrix[5] = 2f / (top - bottom)
+ matrix[6] = 0f
+ matrix[7] = 0f
+
+ matrix[8] = 0f
+ matrix[9] = 0f
+ matrix[10] = -2f / (far - near)
+ matrix[11] = 0f
+
+ matrix[12] = - (right + left) / (right - left)
+ matrix[13] = - (top + bottom) / (top - bottom)
+ matrix[14] = - (far + near) / (far - near)
+ matrix[15] = 1f
+ }
+
+ fun setToIdentity() {
+ matrix[0] = 1.0f
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+ matrix[4] = 0.0f
+ matrix[5] = 1.0f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = 1.0f
+ matrix[11] = 0.0f
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = 0.0f
+ matrix[15] = 1.0f
+ }
+
+ fun mul(other: Matrix4) {
+ mul(other.get())
+ }
+
+ protected fun mul(other: FloatArray) {
+ if (other.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12]
+ temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13]
+ temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14]
+ temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15]
+ temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12]
+ temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13]
+ temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14]
+ temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15]
+ temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12]
+ temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13]
+ temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14]
+ temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15]
+ temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12]
+ temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13]
+ temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14]
+ temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15]
+
+ matrix[0] = temp[0]
+ matrix[1] = temp[1]
+ matrix[2] = temp[2]
+ matrix[3] = temp[3]
+ matrix[4] = temp[4]
+ matrix[5] = temp[5]
+ matrix[6] = temp[6]
+ matrix[7] = temp[7]
+ matrix[8] = temp[8]
+ matrix[9] = temp[9]
+ matrix[10] = temp[10]
+ matrix[11] = temp[11]
+ matrix[12] = temp[12]
+ matrix[13] = temp[13]
+ matrix[14] = temp[14]
+ matrix[15] = temp[15]
+ }
+
+ fun translate(x: Float, y: Float, z: Float) {
+ translateMatrix[12] = x
+ translateMatrix[13] = y
+ translateMatrix[14] = z
+
+ mul(translateMatrix)
+ }
+
+ fun scale(x: Float, y: Float, z: Float) {
+ scaleMatrix[0] = x
+ scaleMatrix[5] = y
+ scaleMatrix[10] = z
+
+ mul(scaleMatrix)
+ }
+
+ fun rotateX(angle: Float) {
+ rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+ rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat()
+ rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateXMatrix)
+ }
+
+ fun rotateY(angle: Float) {
+ rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat()
+ rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateYMatrix)
+ }
+
+ fun rotateZ(angle: Float) {
+ rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat()
+ rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateZMatrix)
+ }
+}
diff --git a/src/com/persesgames/net/NetUtils.kt b/src/com/persesgames/net/NetUtils.kt
new file mode 100644
index 0000000..b59cbb3
--- /dev/null
+++ b/src/com/persesgames/net/NetUtils.kt
@@ -0,0 +1,18 @@
+package com.persesgames.net
+
+import org.w3c.xhr.XMLHttpRequest
+
+/**
+ * User: rnentjes
+ * Date: 30-7-16
+ * Time: 16:39
+ */
+
+fun getUrlAsString(url: String): String {
+ val req = XMLHttpRequest()
+
+ req.open("GET", url, false)
+ req.send(null)
+
+ return req.responseText
+}
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/settings.gradle b/settings.gradle
index 329f712..3181c92 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-rootProject.name = 'kotlin-webgl-test'
+rootProject.name = 'kudens'
diff --git a/src/com/persesgames/game/Game.kt b/src/com/persesgames/game/Game.kt
new file mode 100644
index 0000000..3abdd56
--- /dev/null
+++ b/src/com/persesgames/game/Game.kt
@@ -0,0 +1,155 @@
+package com.persesgames.game
+
+import com.persesgames.texture.Textures
+import org.khronos.webgl.WebGLRenderingContext
+import org.w3c.dom.CanvasRenderingContext2D
+import org.w3c.dom.HTMLCanvasElement
+import org.w3c.dom.HTMLElement
+import kotlin.browser.document
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+enum class DrawMode {
+ LINEAR,
+ NEAREST
+}
+
+class HTMLElements {
+ var container: HTMLElement
+ var webgl: WebGLRenderingContext
+ var canvas2d: CanvasRenderingContext2D
+
+ init {
+ container = document.createElement("div") as HTMLElement
+
+ val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement
+ val canvas = document.createElement("canvas") as HTMLCanvasElement
+
+ container.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
+ webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" )
+ canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" )
+
+ document.body!!.appendChild(container)
+ container.appendChild(webGlCanvas)
+ container.appendChild(canvas)
+
+ webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext
+ canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D
+ }
+}
+
+object Game {
+ var started = false
+ val view: View = View()
+ val html: HTMLElements by lazy { HTMLElements() }
+ var currentScreen: Screen = DefaultScreen()
+ var start = Date().getTime()
+ var currentTime = start
+ var currentDelta = 0f
+ var pause: Boolean = false
+
+ var fps = 0
+ var fpsCount = 0
+ var fpsCountTime = 0f
+
+ fun gl() = html.webgl
+
+ fun resize() {
+ val canvas = gl().canvas
+
+ // Check if the canvas is not the same size.
+ val windowWidth = window.innerWidth.toInt()
+ val windowHeight = window.innerHeight.toInt()
+
+ if (view.lastWindowWidth != windowWidth ||
+ view.lastWindowHeight != windowHeight) {
+ view.lastWindowWidth = windowWidth
+ view.lastWindowHeight = windowHeight
+ view.windowWidth = windowWidth
+ view.windowHeight = windowHeight
+
+ view.updateView()
+
+ val textCanvas = html.canvas2d.canvas
+
+ // Make the canvas the same size
+ canvas.width = view.width.toInt()
+ canvas.height = view.height.toInt()
+
+ textCanvas.width = view.width.toInt()
+ textCanvas.height = view.height.toInt()
+
+ gl().viewport(0, 0, view.width.toInt(), view.height.toInt())
+
+ val left = (windowWidth - view.windowWidth) / 2
+ val top = (windowHeight - view.windowHeight) / 2
+
+ canvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ textCanvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ }
+ }
+
+ fun start(startScreen: Screen) {
+ if (started) {
+ throw IllegalStateException("You can only start a game once!")
+ }
+
+ setScreen(startScreen)
+
+ // start game loop
+ started = true
+ gameLoop()
+ }
+
+ fun setScreen(screen: Screen) {
+ currentScreen.closeResources()
+
+ currentScreen = screen
+
+ currentScreen.loadResources()
+ }
+
+ fun gameLoop() {
+ if (!Textures.ready()) {
+ Game.gl().clearColor(1f, 1f, 1f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ } else {
+ resize()
+
+ if (!pause) {
+ html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble());
+
+ Game.gl().clearColor(0f, 0f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+
+ Game.gl().enable(WebGLRenderingContext.BLEND);
+ Game.gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA); //ONE_MINUS_DST_ALPHA);
+
+ val time = Date().getTime()
+ currentDelta = (time - currentTime) / 1000f
+ currentTime = time
+
+ val timeInSeconds = (currentTime - start) / 1000f
+
+ fpsCountTime += currentDelta
+ fpsCount++
+ while (fpsCountTime > 1f) {
+ fps = fpsCount
+ fpsCountTime -= 1f
+ fpsCount = 0
+ }
+
+ currentScreen.update(timeInSeconds, currentDelta);
+ currentScreen.render()
+ }
+ }
+
+ window.requestAnimationFrame {
+ gameLoop()
+ }
+ }
+
+}
diff --git a/src/com/persesgames/game/Screen.kt b/src/com/persesgames/game/Screen.kt
new file mode 100644
index 0000000..6fb558e
--- /dev/null
+++ b/src/com/persesgames/game/Screen.kt
@@ -0,0 +1,35 @@
+package com.persesgames.game
+
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+abstract class Screen {
+
+ open fun loadResources() {
+
+ }
+
+ open fun closeResources() {
+
+ }
+
+ abstract fun update(time: Float, delta: Float)
+
+ abstract fun render()
+
+}
+
+
+class DefaultScreen: Screen() {
+ override fun update(time: Float, delta: Float) {
+ }
+
+ override fun render() {
+ // show loading message?
+ Game.gl().clearColor(1f, 1f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/game/View.kt b/src/com/persesgames/game/View.kt
new file mode 100644
index 0000000..e5590e0
--- /dev/null
+++ b/src/com/persesgames/game/View.kt
@@ -0,0 +1,221 @@
+package com.persesgames.game
+
+import com.persesgames.math.Matrix4
+
+enum class ViewType {
+ PROJECTION,
+ WIDTH,
+ HEIGHT,
+ ABSOLUTE
+}
+
+class View(
+ var lastWindowWidth: Int = 2000,
+ var lastWindowHeight: Int = 1000,
+ var windowWidth: Int = 2000,
+ var windowHeight: Int = 1000,
+ var width: Float = 1024f,
+ var height: Float = 1024f,
+ var angle: Float = 60f,
+ var near: Float = -0.1f,
+ var far: Float = -100f,
+ var minAspectRatio: Float = 1f,
+ var maxAspectRatio: Float = 1f,
+ var leftOffset: Int = 0,
+ var bottomOffset: Int = 0,
+ var viewType: ViewType = ViewType.WIDTH,
+ var drawMode: DrawMode = DrawMode.LINEAR) {
+ var vMatrix = Matrix4()
+ var aspectRatio = 1f
+
+ init {
+ updateView()
+ }
+
+ fun requestFullscreen() {
+ println("Requesting fullscreen")
+ js("""
+ if (document.webkitFullscreenElement) {
+ document.webkitCancelFullScreen();
+ } else {
+ document.documentElement.webkitRequestFullScreen();
+ }
+ """)
+ //if (document.fullscreenEnabled) {
+ // println("fullscreen Enabled")
+ //Game.html.container.requestFullscreen()
+ //document.documentElement?.requestFullscreen()
+ //}
+ }
+
+ fun updateView() {
+ aspectRatio = windowWidth / windowHeight.toFloat()
+
+ if (aspectRatio < minAspectRatio) {
+ aspectRatio = minAspectRatio
+
+ windowHeight = (windowWidth / aspectRatio).toInt()
+ }
+
+ if (aspectRatio > maxAspectRatio) {
+ aspectRatio = maxAspectRatio
+
+ windowWidth = (windowHeight * aspectRatio).toInt()
+ }
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.WIDTH -> {
+ height = width / aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.HEIGHT -> {
+ width = height * aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.PROJECTION -> {
+ vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far);
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ //println("width: $width, height: $height")
+ }
+
+ fun screenToGameCoordX(screenX: Float): Float {
+ var result = screenX
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.HEIGHT -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun screenToGameCoordY(screenY: Float): Float {
+ var result = screenY
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.HEIGHT -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordX(gameX: Float): Float {
+ var result = gameX
+ val normalizedX = gameX + (width / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.HEIGHT -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordY(gameY: Float): Float {
+ var result = gameY
+ val normalizedY = gameY + (height / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.HEIGHT -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun setToWidth(width: Float) {
+ this.width = width
+ this.viewType = ViewType.WIDTH
+
+ updateView()
+ }
+
+ fun setToHeight(height: Float) {
+ this.height = height
+ this.viewType = ViewType.HEIGHT
+
+ updateView()
+ }
+
+ fun setProjection(angle: Float) {
+ this.angle = angle
+ this.viewType = ViewType.PROJECTION
+
+ updateView()
+ }
+
+ fun setNear(near: Float) {
+ this.near = near
+
+ updateView()
+ }
+
+ fun setFar(far: Float) {
+ this.far = far
+
+ updateView()
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/input/Keys.kt b/src/com/persesgames/input/Keys.kt
new file mode 100644
index 0000000..6705c67
--- /dev/null
+++ b/src/com/persesgames/input/Keys.kt
@@ -0,0 +1,141 @@
+package com.persesgames.input
+
+import com.persesgames.game.Game
+import org.w3c.dom.events.Event
+import org.w3c.dom.events.KeyboardEvent
+import org.w3c.dom.events.MouseEvent
+import java.util.*
+import kotlin.browser.document
+import kotlin.dom.on
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 12:18
+ */
+
+enum class KeyCode(val keyCode: Int) {
+ LEFT(37),
+ UP(38),
+ DOWN(40),
+ RIGHT(39),
+ SPACE(32),
+ MINUS(109),
+ PLUS(107),
+}
+
+interface InputProcessor {
+
+ fun keyPressed(charCode: Int)
+
+ fun keyDown(keyCode: Int)
+
+ fun keyUp(keyCode: Int)
+
+ fun pointerClick(pointer: Int, x: Float, y: Float)
+
+}
+
+open class EmptyInputProcessor : InputProcessor {
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ }
+
+ override fun keyDown(keyCode: Int) {
+ }
+
+ override fun keyPressed(charCode: Int) {
+ }
+
+ override fun keyUp(keyCode: Int) {
+ }
+
+
+}
+
+object Keys {
+
+ private val keys: MutableMap = HashMap();
+ private var inputProcesser: InputProcessor = EmptyInputProcessor()
+
+ init {
+ val body = document.body
+ if (body != null) {
+ body.on("keydown", true) {
+ Keys.keyDown(it)
+ }
+
+ body.on("keyup", true) {
+ Keys.keyUp(it)
+ }
+
+ body.on("keypress", true) {
+ Keys.keyPress(it)
+ }
+
+ body.on("click", true) {
+ Keys.mouseClick(it)
+ }
+
+ body.on("mousedown", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mouseup", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mousemove", true) {
+ Keys.mouseMove(it)
+ }
+ }
+ }
+
+ fun setInputProcessor(processor: InputProcessor) {
+ this.inputProcesser = processor
+ }
+
+ private fun keyDown(key: Event) {
+ if (key is KeyboardEvent) {
+ keys.put(key.keyCode, Date().getTime())
+
+ inputProcesser.keyDown(key.keyCode)
+ }
+ }
+
+ private fun keyUp(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyUp(key.keyCode)
+
+ keys.remove(key.keyCode)
+ }
+ }
+
+ private fun keyPress(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyPressed(key.charCode)
+ }
+ }
+
+ private fun mouseClick(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+ inputProcesser.pointerClick(event.button.toInt(), vx, vy)
+ }
+ }
+
+ private fun mouseMove(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+
+ }
+ }
+
+ fun isDown(keyCode: Int) = keys.containsKey(keyCode)
+
+ fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode)
+
+}
diff --git a/src/com/persesgames/map/Map.kt b/src/com/persesgames/map/Map.kt
new file mode 100644
index 0000000..b5d7bc8
--- /dev/null
+++ b/src/com/persesgames/map/Map.kt
@@ -0,0 +1,9 @@
+package com.persesgames.map
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+open class Map {
+
+}
diff --git a/src/com/persesgames/map/tiled/TiledMap.kt b/src/com/persesgames/map/tiled/TiledMap.kt
new file mode 100644
index 0000000..a84a5a3
--- /dev/null
+++ b/src/com/persesgames/map/tiled/TiledMap.kt
@@ -0,0 +1,211 @@
+package com.persesgames.map.tiled
+
+import com.persesgames.net.getUrlAsString
+import com.persesgames.texture.Texture
+import com.persesgames.texture.Textures
+import java.util.*
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+class MapData {
+ var version: Int = 1
+ var properties: MutableMap = HashMap()
+ var layers: Array? = null
+ var tilesets: Array? = null
+
+ var height: Int = 0
+ var width: Int = 0
+
+ var nextobjectid: Int = 0
+ var orientation: String = "orthogonal"
+ var renderorder: String = "right-down"
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+}
+
+class MapLayer {
+ var properties: MutableMap = HashMap()
+
+ var data: Array? = null
+ var encoding: String = ""
+ var x: Int = 0
+ var y: Int = 0
+ var width: Int = 0
+ var height: Int = 0
+ var name: String = ""
+ var opacity: Float = 1f
+ var type: String = ""
+ var visible: Boolean = true
+ var draworder: String = ""
+}
+
+class MapTileset {
+ var properties: MutableMap = HashMap()
+
+ var firstgid: Int = 0
+ var image: String = ""
+ var imageheight: Int = 0
+ var imagewidth: Int = 0
+ var margin: Int = 0
+ var name: String = ""
+ var spacing: Int = 0
+ var tilecount: Int = 0
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+ var tileproperties: MutableMap> = HashMap()
+}
+
+class TilesetIndex(
+ val texture: Texture?,
+ val tcLeft: Float,
+ val tcTop: Float,
+ val tcRight: Float,
+ val tcBottom: Float,
+ val scale: Float
+ ) {
+ constructor() : this(null, 0f, 0f, 0f, 0f, 0f)
+
+ fun render(x: Float, y: Float) {
+ texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+}
+
+class TiledMap(dir: String = "", url: String) {
+ val properties: Map = HashMap()
+ val data: MapData
+ val tileset: Array
+ val tiles: Array
+ var first = true
+ //var tilesetIndex: Array = Array(0, { TilesetIndex() })
+
+ init {
+ var tileDir = dir
+ if (!tileDir.isEmpty() && !tileDir.endsWith("/")) {
+ tileDir = tileDir + "/"
+ }
+
+ data = JSON.parse(getUrlAsString(tileDir + url))
+ println("map data is loaded")
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ tileset = Array(tilesets.size, { "" })
+ var maxGid = 0
+ for (index in 0..tilesets.size - 1) {
+ tileset[index] = tilesets[index].name
+ Textures.load(tilesets[index].name, tileDir + tilesets[index].image)
+ maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount)
+ }
+
+ tiles = Array(maxGid, { TilesetIndex() })
+ } else {
+ tileset = Array(0, { "" })
+ tiles = Array(0, { TilesetIndex() })
+ }
+
+ cacheTiles()
+ }
+
+ fun cacheTiles() {
+ if (!Textures.ready()) {
+ window.setTimeout({ cacheTiles() }, 10)
+ } else {
+ val tilesets = data.tilesets
+ var tcLeft = 0f
+ var tcTop = 0f
+ var tcRight = 0f
+ var tcBottom = 0f
+
+ if (tilesets != null) {
+
+
+ for (tileset in tilesets) {
+ val tilesHor = tileset.imagewidth / tileset.tilewidth
+ val tilesVer = tileset.imageheight / tileset.tileheight
+ val scale = (tileset.tilewidth / tileset.imagewidth.toFloat())
+
+ for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) {
+ val texture = Textures.get(tileset.name)
+
+ val gid = index - tileset.firstgid
+
+ val xi = gid % tilesHor
+ var yi = gid / tilesHor
+ yi = tilesVer - yi - 1
+ val tw = 1f / tilesHor.toFloat()
+ val th = 1f / tilesVer.toFloat()
+
+ val pixelW = 0.1f / tileset.tilewidth
+ val pixelH = 0.1f / tileset.tileheight
+
+ tcLeft = xi * tw
+ tcRight = tcLeft + tw
+
+ // switch up/down because of texture coord 0,0 in left bottom corner
+ tcBottom = yi * th
+ tcTop = tcBottom + th
+
+ tcLeft += pixelW
+ tcRight -= pixelW
+
+ tcBottom += pixelH
+ tcTop -= pixelH
+
+ tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+ }
+ }
+ }
+ }
+
+ fun drawTile(tile: Int, x: Float, y: Float) {
+ tiles[tile].render(x, y)
+ }
+
+ fun drawLayer(layerIndex: Int, xo: Float, yo: Float) {
+ var x = 0f
+ var y = 0f
+ val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)")
+ val layer = layers[layerIndex]
+
+ val layerData = layer.data
+ if (layerData != null) {
+ for (index in layerData.indices) {
+ // todo: determine if in view
+ // todo: determine tilewidth
+ //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) {
+ drawTile(layerData[index], xo + x * 128f, yo + y * 128f)
+
+ when (data.renderorder) {
+ "right-down" -> {
+ x++
+ if (x >= layer.width) {
+ x = 0f
+ y--
+ }
+ }
+ else -> {
+ throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this")
+ }
+ }
+ //}
+ }
+ }
+
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
+
+ tx.render()
+ }
+ }
+ }
+
+
+ first = false
+ }
+}
diff --git a/src/com/persesgames/math/Matrix4.kt b/src/com/persesgames/math/Matrix4.kt
new file mode 100644
index 0000000..3cb4ed4
--- /dev/null
+++ b/src/com/persesgames/math/Matrix4.kt
@@ -0,0 +1,192 @@
+package com.persesgames.math
+
+import org.khronos.webgl.Float32Array
+
+/**
+ * User: rnentjes
+ * Date: 17-4-16
+ * Time: 15:43
+ */
+class Matrix4 {
+
+ internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ internal var temp = FloatArray(16)
+
+ private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ fun get(): FloatArray {
+ return matrix
+ }
+
+ fun getFloat32Array() = Float32Array(get().toTypedArray())
+
+ fun set(values: FloatArray) {
+ if (values.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ matrix = values
+ }
+
+ fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) {
+ val r = (angle / 180f * Math.PI).toFloat()
+ val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat()
+
+ matrix[0] = f / imageAspectRatio
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+
+ matrix[4] = 0.0f
+ matrix[5] = f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = -(far + near) / (far - near)
+ matrix[11] = -1.0f
+
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = -(2.0f * far * near) / (far - near)
+ matrix[15] = 0.0f
+ }
+
+ fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) {
+ matrix[0] = 2f / (right - left)
+ matrix[1] = 0f
+ matrix[2] = 0f
+ matrix[3] = 0f
+
+ matrix[4] = 0f
+ matrix[5] = 2f / (top - bottom)
+ matrix[6] = 0f
+ matrix[7] = 0f
+
+ matrix[8] = 0f
+ matrix[9] = 0f
+ matrix[10] = -2f / (far - near)
+ matrix[11] = 0f
+
+ matrix[12] = - (right + left) / (right - left)
+ matrix[13] = - (top + bottom) / (top - bottom)
+ matrix[14] = - (far + near) / (far - near)
+ matrix[15] = 1f
+ }
+
+ fun setToIdentity() {
+ matrix[0] = 1.0f
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+ matrix[4] = 0.0f
+ matrix[5] = 1.0f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = 1.0f
+ matrix[11] = 0.0f
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = 0.0f
+ matrix[15] = 1.0f
+ }
+
+ fun mul(other: Matrix4) {
+ mul(other.get())
+ }
+
+ protected fun mul(other: FloatArray) {
+ if (other.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12]
+ temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13]
+ temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14]
+ temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15]
+ temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12]
+ temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13]
+ temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14]
+ temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15]
+ temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12]
+ temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13]
+ temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14]
+ temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15]
+ temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12]
+ temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13]
+ temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14]
+ temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15]
+
+ matrix[0] = temp[0]
+ matrix[1] = temp[1]
+ matrix[2] = temp[2]
+ matrix[3] = temp[3]
+ matrix[4] = temp[4]
+ matrix[5] = temp[5]
+ matrix[6] = temp[6]
+ matrix[7] = temp[7]
+ matrix[8] = temp[8]
+ matrix[9] = temp[9]
+ matrix[10] = temp[10]
+ matrix[11] = temp[11]
+ matrix[12] = temp[12]
+ matrix[13] = temp[13]
+ matrix[14] = temp[14]
+ matrix[15] = temp[15]
+ }
+
+ fun translate(x: Float, y: Float, z: Float) {
+ translateMatrix[12] = x
+ translateMatrix[13] = y
+ translateMatrix[14] = z
+
+ mul(translateMatrix)
+ }
+
+ fun scale(x: Float, y: Float, z: Float) {
+ scaleMatrix[0] = x
+ scaleMatrix[5] = y
+ scaleMatrix[10] = z
+
+ mul(scaleMatrix)
+ }
+
+ fun rotateX(angle: Float) {
+ rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+ rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat()
+ rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateXMatrix)
+ }
+
+ fun rotateY(angle: Float) {
+ rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat()
+ rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateYMatrix)
+ }
+
+ fun rotateZ(angle: Float) {
+ rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat()
+ rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateZMatrix)
+ }
+}
diff --git a/src/com/persesgames/net/NetUtils.kt b/src/com/persesgames/net/NetUtils.kt
new file mode 100644
index 0000000..b59cbb3
--- /dev/null
+++ b/src/com/persesgames/net/NetUtils.kt
@@ -0,0 +1,18 @@
+package com.persesgames.net
+
+import org.w3c.xhr.XMLHttpRequest
+
+/**
+ * User: rnentjes
+ * Date: 30-7-16
+ * Time: 16:39
+ */
+
+fun getUrlAsString(url: String): String {
+ val req = XMLHttpRequest()
+
+ req.open("GET", url, false)
+ req.send(null)
+
+ return req.responseText
+}
diff --git a/src/com/persesgames/shader/ShaderProgram.kt b/src/com/persesgames/shader/ShaderProgram.kt
new file mode 100644
index 0000000..3c3aad5
--- /dev/null
+++ b/src/com/persesgames/shader/ShaderProgram.kt
@@ -0,0 +1,110 @@
+package com.persesgames.shader
+
+import org.khronos.webgl.*
+
+/**
+ * User: rnentjes
+ * Date: 17-4-16
+ * Time: 15:15
+ */
+
+class ShaderProgram(
+ val webgl: WebGLRenderingContext,
+ val drawType: Int,
+ vertexShaderSource: String,
+ fragmentShaderSource: String,
+ val vainfo: Array,
+ val setter: (program: ShaderProgram, data: T) -> Unit) {
+
+ var shaderProgram: WebGLProgram
+ var vertex: WebGLShader
+ var fragment: WebGLShader
+
+ var verticesBlockSize = 0
+ var drawLength = 0
+
+ init {
+ vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER)
+ fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER)
+
+ shaderProgram = webgl.createProgram() ?: throw IllegalStateException("Unable to request shader program from webgl context!")
+ webgl.attachShader(shaderProgram, vertex)
+ webgl.attachShader(shaderProgram, fragment)
+ webgl.linkProgram(shaderProgram)
+
+ if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) {
+ println(webgl.getProgramInfoLog(shaderProgram))
+ throw IllegalStateException("Unable to compile shader program!")
+ }
+
+ webgl.useProgram(shaderProgram)
+
+ this.verticesBlockSize = 0;
+
+ // set attribute locations...
+ for (info in vainfo.iterator()) {
+ info.location = webgl.getAttribLocation(shaderProgram, info.locationName)
+ info.offset = verticesBlockSize;
+
+ verticesBlockSize += info.numElements;
+ println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}");
+ }
+
+ when(drawType) {
+ WebGLRenderingContext.TRIANGLES -> {
+ drawLength = verticesBlockSize * 3
+ }
+ else -> {
+ drawLength = verticesBlockSize
+ }
+ }
+
+ println("verticesBlockSize $verticesBlockSize");
+
+ println("ShaderProgram constructor done");
+ }
+
+ private fun compileShader(source: String, type: Int): WebGLShader {
+ val result: WebGLShader
+
+ result = webgl.createShader(type) ?: throw IllegalStateException("Unable to request shader from webgl context!")
+ webgl.shaderSource(result, source)
+ webgl.compileShader(result)
+
+ if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) {
+ throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}")
+ }
+
+ return result
+ }
+
+ fun begin(attribBuffer: WebGLBuffer, userdata: T) {
+ webgl.useProgram(shaderProgram);
+ webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer);
+
+ // set attribute locations...
+ for (info in vainfo.iterator()) {
+ webgl.enableVertexAttribArray(info.location)
+ webgl.vertexAttribPointer(info.location, info.numElements, WebGLRenderingContext.FLOAT, false, verticesBlockSize * 4, info.offset * 4)
+ }
+
+ setter(this, userdata)
+ }
+
+ fun end() {
+ for (info in vainfo.iterator()) {
+ webgl.disableVertexAttribArray(info.location);
+ }
+ webgl.useProgram(null)
+ }
+
+ fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location);
+
+ fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location);
+
+ fun setUniform1f(location: String, value: Float) { webgl.uniform1f(getUniformLocation(location), value); }
+ fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); }
+ fun setUniform1i(location: String, value: Int) { webgl.uniform1i(getUniformLocation(location), value); }
+ fun setUniformMatrix4fv(location: String, value: Float32Array) { webgl.uniformMatrix4fv(getUniformLocation(location), false, value); }
+
+}
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/settings.gradle b/settings.gradle
index 329f712..3181c92 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-rootProject.name = 'kotlin-webgl-test'
+rootProject.name = 'kudens'
diff --git a/src/com/persesgames/game/Game.kt b/src/com/persesgames/game/Game.kt
new file mode 100644
index 0000000..3abdd56
--- /dev/null
+++ b/src/com/persesgames/game/Game.kt
@@ -0,0 +1,155 @@
+package com.persesgames.game
+
+import com.persesgames.texture.Textures
+import org.khronos.webgl.WebGLRenderingContext
+import org.w3c.dom.CanvasRenderingContext2D
+import org.w3c.dom.HTMLCanvasElement
+import org.w3c.dom.HTMLElement
+import kotlin.browser.document
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+enum class DrawMode {
+ LINEAR,
+ NEAREST
+}
+
+class HTMLElements {
+ var container: HTMLElement
+ var webgl: WebGLRenderingContext
+ var canvas2d: CanvasRenderingContext2D
+
+ init {
+ container = document.createElement("div") as HTMLElement
+
+ val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement
+ val canvas = document.createElement("canvas") as HTMLCanvasElement
+
+ container.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
+ webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" )
+ canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" )
+
+ document.body!!.appendChild(container)
+ container.appendChild(webGlCanvas)
+ container.appendChild(canvas)
+
+ webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext
+ canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D
+ }
+}
+
+object Game {
+ var started = false
+ val view: View = View()
+ val html: HTMLElements by lazy { HTMLElements() }
+ var currentScreen: Screen = DefaultScreen()
+ var start = Date().getTime()
+ var currentTime = start
+ var currentDelta = 0f
+ var pause: Boolean = false
+
+ var fps = 0
+ var fpsCount = 0
+ var fpsCountTime = 0f
+
+ fun gl() = html.webgl
+
+ fun resize() {
+ val canvas = gl().canvas
+
+ // Check if the canvas is not the same size.
+ val windowWidth = window.innerWidth.toInt()
+ val windowHeight = window.innerHeight.toInt()
+
+ if (view.lastWindowWidth != windowWidth ||
+ view.lastWindowHeight != windowHeight) {
+ view.lastWindowWidth = windowWidth
+ view.lastWindowHeight = windowHeight
+ view.windowWidth = windowWidth
+ view.windowHeight = windowHeight
+
+ view.updateView()
+
+ val textCanvas = html.canvas2d.canvas
+
+ // Make the canvas the same size
+ canvas.width = view.width.toInt()
+ canvas.height = view.height.toInt()
+
+ textCanvas.width = view.width.toInt()
+ textCanvas.height = view.height.toInt()
+
+ gl().viewport(0, 0, view.width.toInt(), view.height.toInt())
+
+ val left = (windowWidth - view.windowWidth) / 2
+ val top = (windowHeight - view.windowHeight) / 2
+
+ canvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ textCanvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ }
+ }
+
+ fun start(startScreen: Screen) {
+ if (started) {
+ throw IllegalStateException("You can only start a game once!")
+ }
+
+ setScreen(startScreen)
+
+ // start game loop
+ started = true
+ gameLoop()
+ }
+
+ fun setScreen(screen: Screen) {
+ currentScreen.closeResources()
+
+ currentScreen = screen
+
+ currentScreen.loadResources()
+ }
+
+ fun gameLoop() {
+ if (!Textures.ready()) {
+ Game.gl().clearColor(1f, 1f, 1f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ } else {
+ resize()
+
+ if (!pause) {
+ html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble());
+
+ Game.gl().clearColor(0f, 0f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+
+ Game.gl().enable(WebGLRenderingContext.BLEND);
+ Game.gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA); //ONE_MINUS_DST_ALPHA);
+
+ val time = Date().getTime()
+ currentDelta = (time - currentTime) / 1000f
+ currentTime = time
+
+ val timeInSeconds = (currentTime - start) / 1000f
+
+ fpsCountTime += currentDelta
+ fpsCount++
+ while (fpsCountTime > 1f) {
+ fps = fpsCount
+ fpsCountTime -= 1f
+ fpsCount = 0
+ }
+
+ currentScreen.update(timeInSeconds, currentDelta);
+ currentScreen.render()
+ }
+ }
+
+ window.requestAnimationFrame {
+ gameLoop()
+ }
+ }
+
+}
diff --git a/src/com/persesgames/game/Screen.kt b/src/com/persesgames/game/Screen.kt
new file mode 100644
index 0000000..6fb558e
--- /dev/null
+++ b/src/com/persesgames/game/Screen.kt
@@ -0,0 +1,35 @@
+package com.persesgames.game
+
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+abstract class Screen {
+
+ open fun loadResources() {
+
+ }
+
+ open fun closeResources() {
+
+ }
+
+ abstract fun update(time: Float, delta: Float)
+
+ abstract fun render()
+
+}
+
+
+class DefaultScreen: Screen() {
+ override fun update(time: Float, delta: Float) {
+ }
+
+ override fun render() {
+ // show loading message?
+ Game.gl().clearColor(1f, 1f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/game/View.kt b/src/com/persesgames/game/View.kt
new file mode 100644
index 0000000..e5590e0
--- /dev/null
+++ b/src/com/persesgames/game/View.kt
@@ -0,0 +1,221 @@
+package com.persesgames.game
+
+import com.persesgames.math.Matrix4
+
+enum class ViewType {
+ PROJECTION,
+ WIDTH,
+ HEIGHT,
+ ABSOLUTE
+}
+
+class View(
+ var lastWindowWidth: Int = 2000,
+ var lastWindowHeight: Int = 1000,
+ var windowWidth: Int = 2000,
+ var windowHeight: Int = 1000,
+ var width: Float = 1024f,
+ var height: Float = 1024f,
+ var angle: Float = 60f,
+ var near: Float = -0.1f,
+ var far: Float = -100f,
+ var minAspectRatio: Float = 1f,
+ var maxAspectRatio: Float = 1f,
+ var leftOffset: Int = 0,
+ var bottomOffset: Int = 0,
+ var viewType: ViewType = ViewType.WIDTH,
+ var drawMode: DrawMode = DrawMode.LINEAR) {
+ var vMatrix = Matrix4()
+ var aspectRatio = 1f
+
+ init {
+ updateView()
+ }
+
+ fun requestFullscreen() {
+ println("Requesting fullscreen")
+ js("""
+ if (document.webkitFullscreenElement) {
+ document.webkitCancelFullScreen();
+ } else {
+ document.documentElement.webkitRequestFullScreen();
+ }
+ """)
+ //if (document.fullscreenEnabled) {
+ // println("fullscreen Enabled")
+ //Game.html.container.requestFullscreen()
+ //document.documentElement?.requestFullscreen()
+ //}
+ }
+
+ fun updateView() {
+ aspectRatio = windowWidth / windowHeight.toFloat()
+
+ if (aspectRatio < minAspectRatio) {
+ aspectRatio = minAspectRatio
+
+ windowHeight = (windowWidth / aspectRatio).toInt()
+ }
+
+ if (aspectRatio > maxAspectRatio) {
+ aspectRatio = maxAspectRatio
+
+ windowWidth = (windowHeight * aspectRatio).toInt()
+ }
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.WIDTH -> {
+ height = width / aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.HEIGHT -> {
+ width = height * aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.PROJECTION -> {
+ vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far);
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ //println("width: $width, height: $height")
+ }
+
+ fun screenToGameCoordX(screenX: Float): Float {
+ var result = screenX
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.HEIGHT -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun screenToGameCoordY(screenY: Float): Float {
+ var result = screenY
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.HEIGHT -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordX(gameX: Float): Float {
+ var result = gameX
+ val normalizedX = gameX + (width / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.HEIGHT -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordY(gameY: Float): Float {
+ var result = gameY
+ val normalizedY = gameY + (height / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.HEIGHT -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun setToWidth(width: Float) {
+ this.width = width
+ this.viewType = ViewType.WIDTH
+
+ updateView()
+ }
+
+ fun setToHeight(height: Float) {
+ this.height = height
+ this.viewType = ViewType.HEIGHT
+
+ updateView()
+ }
+
+ fun setProjection(angle: Float) {
+ this.angle = angle
+ this.viewType = ViewType.PROJECTION
+
+ updateView()
+ }
+
+ fun setNear(near: Float) {
+ this.near = near
+
+ updateView()
+ }
+
+ fun setFar(far: Float) {
+ this.far = far
+
+ updateView()
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/input/Keys.kt b/src/com/persesgames/input/Keys.kt
new file mode 100644
index 0000000..6705c67
--- /dev/null
+++ b/src/com/persesgames/input/Keys.kt
@@ -0,0 +1,141 @@
+package com.persesgames.input
+
+import com.persesgames.game.Game
+import org.w3c.dom.events.Event
+import org.w3c.dom.events.KeyboardEvent
+import org.w3c.dom.events.MouseEvent
+import java.util.*
+import kotlin.browser.document
+import kotlin.dom.on
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 12:18
+ */
+
+enum class KeyCode(val keyCode: Int) {
+ LEFT(37),
+ UP(38),
+ DOWN(40),
+ RIGHT(39),
+ SPACE(32),
+ MINUS(109),
+ PLUS(107),
+}
+
+interface InputProcessor {
+
+ fun keyPressed(charCode: Int)
+
+ fun keyDown(keyCode: Int)
+
+ fun keyUp(keyCode: Int)
+
+ fun pointerClick(pointer: Int, x: Float, y: Float)
+
+}
+
+open class EmptyInputProcessor : InputProcessor {
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ }
+
+ override fun keyDown(keyCode: Int) {
+ }
+
+ override fun keyPressed(charCode: Int) {
+ }
+
+ override fun keyUp(keyCode: Int) {
+ }
+
+
+}
+
+object Keys {
+
+ private val keys: MutableMap = HashMap();
+ private var inputProcesser: InputProcessor = EmptyInputProcessor()
+
+ init {
+ val body = document.body
+ if (body != null) {
+ body.on("keydown", true) {
+ Keys.keyDown(it)
+ }
+
+ body.on("keyup", true) {
+ Keys.keyUp(it)
+ }
+
+ body.on("keypress", true) {
+ Keys.keyPress(it)
+ }
+
+ body.on("click", true) {
+ Keys.mouseClick(it)
+ }
+
+ body.on("mousedown", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mouseup", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mousemove", true) {
+ Keys.mouseMove(it)
+ }
+ }
+ }
+
+ fun setInputProcessor(processor: InputProcessor) {
+ this.inputProcesser = processor
+ }
+
+ private fun keyDown(key: Event) {
+ if (key is KeyboardEvent) {
+ keys.put(key.keyCode, Date().getTime())
+
+ inputProcesser.keyDown(key.keyCode)
+ }
+ }
+
+ private fun keyUp(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyUp(key.keyCode)
+
+ keys.remove(key.keyCode)
+ }
+ }
+
+ private fun keyPress(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyPressed(key.charCode)
+ }
+ }
+
+ private fun mouseClick(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+ inputProcesser.pointerClick(event.button.toInt(), vx, vy)
+ }
+ }
+
+ private fun mouseMove(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+
+ }
+ }
+
+ fun isDown(keyCode: Int) = keys.containsKey(keyCode)
+
+ fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode)
+
+}
diff --git a/src/com/persesgames/map/Map.kt b/src/com/persesgames/map/Map.kt
new file mode 100644
index 0000000..b5d7bc8
--- /dev/null
+++ b/src/com/persesgames/map/Map.kt
@@ -0,0 +1,9 @@
+package com.persesgames.map
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+open class Map {
+
+}
diff --git a/src/com/persesgames/map/tiled/TiledMap.kt b/src/com/persesgames/map/tiled/TiledMap.kt
new file mode 100644
index 0000000..a84a5a3
--- /dev/null
+++ b/src/com/persesgames/map/tiled/TiledMap.kt
@@ -0,0 +1,211 @@
+package com.persesgames.map.tiled
+
+import com.persesgames.net.getUrlAsString
+import com.persesgames.texture.Texture
+import com.persesgames.texture.Textures
+import java.util.*
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+class MapData {
+ var version: Int = 1
+ var properties: MutableMap = HashMap()
+ var layers: Array? = null
+ var tilesets: Array? = null
+
+ var height: Int = 0
+ var width: Int = 0
+
+ var nextobjectid: Int = 0
+ var orientation: String = "orthogonal"
+ var renderorder: String = "right-down"
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+}
+
+class MapLayer {
+ var properties: MutableMap = HashMap()
+
+ var data: Array? = null
+ var encoding: String = ""
+ var x: Int = 0
+ var y: Int = 0
+ var width: Int = 0
+ var height: Int = 0
+ var name: String = ""
+ var opacity: Float = 1f
+ var type: String = ""
+ var visible: Boolean = true
+ var draworder: String = ""
+}
+
+class MapTileset {
+ var properties: MutableMap = HashMap()
+
+ var firstgid: Int = 0
+ var image: String = ""
+ var imageheight: Int = 0
+ var imagewidth: Int = 0
+ var margin: Int = 0
+ var name: String = ""
+ var spacing: Int = 0
+ var tilecount: Int = 0
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+ var tileproperties: MutableMap> = HashMap()
+}
+
+class TilesetIndex(
+ val texture: Texture?,
+ val tcLeft: Float,
+ val tcTop: Float,
+ val tcRight: Float,
+ val tcBottom: Float,
+ val scale: Float
+ ) {
+ constructor() : this(null, 0f, 0f, 0f, 0f, 0f)
+
+ fun render(x: Float, y: Float) {
+ texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+}
+
+class TiledMap(dir: String = "", url: String) {
+ val properties: Map = HashMap()
+ val data: MapData
+ val tileset: Array
+ val tiles: Array
+ var first = true
+ //var tilesetIndex: Array = Array(0, { TilesetIndex() })
+
+ init {
+ var tileDir = dir
+ if (!tileDir.isEmpty() && !tileDir.endsWith("/")) {
+ tileDir = tileDir + "/"
+ }
+
+ data = JSON.parse(getUrlAsString(tileDir + url))
+ println("map data is loaded")
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ tileset = Array(tilesets.size, { "" })
+ var maxGid = 0
+ for (index in 0..tilesets.size - 1) {
+ tileset[index] = tilesets[index].name
+ Textures.load(tilesets[index].name, tileDir + tilesets[index].image)
+ maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount)
+ }
+
+ tiles = Array(maxGid, { TilesetIndex() })
+ } else {
+ tileset = Array(0, { "" })
+ tiles = Array(0, { TilesetIndex() })
+ }
+
+ cacheTiles()
+ }
+
+ fun cacheTiles() {
+ if (!Textures.ready()) {
+ window.setTimeout({ cacheTiles() }, 10)
+ } else {
+ val tilesets = data.tilesets
+ var tcLeft = 0f
+ var tcTop = 0f
+ var tcRight = 0f
+ var tcBottom = 0f
+
+ if (tilesets != null) {
+
+
+ for (tileset in tilesets) {
+ val tilesHor = tileset.imagewidth / tileset.tilewidth
+ val tilesVer = tileset.imageheight / tileset.tileheight
+ val scale = (tileset.tilewidth / tileset.imagewidth.toFloat())
+
+ for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) {
+ val texture = Textures.get(tileset.name)
+
+ val gid = index - tileset.firstgid
+
+ val xi = gid % tilesHor
+ var yi = gid / tilesHor
+ yi = tilesVer - yi - 1
+ val tw = 1f / tilesHor.toFloat()
+ val th = 1f / tilesVer.toFloat()
+
+ val pixelW = 0.1f / tileset.tilewidth
+ val pixelH = 0.1f / tileset.tileheight
+
+ tcLeft = xi * tw
+ tcRight = tcLeft + tw
+
+ // switch up/down because of texture coord 0,0 in left bottom corner
+ tcBottom = yi * th
+ tcTop = tcBottom + th
+
+ tcLeft += pixelW
+ tcRight -= pixelW
+
+ tcBottom += pixelH
+ tcTop -= pixelH
+
+ tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+ }
+ }
+ }
+ }
+
+ fun drawTile(tile: Int, x: Float, y: Float) {
+ tiles[tile].render(x, y)
+ }
+
+ fun drawLayer(layerIndex: Int, xo: Float, yo: Float) {
+ var x = 0f
+ var y = 0f
+ val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)")
+ val layer = layers[layerIndex]
+
+ val layerData = layer.data
+ if (layerData != null) {
+ for (index in layerData.indices) {
+ // todo: determine if in view
+ // todo: determine tilewidth
+ //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) {
+ drawTile(layerData[index], xo + x * 128f, yo + y * 128f)
+
+ when (data.renderorder) {
+ "right-down" -> {
+ x++
+ if (x >= layer.width) {
+ x = 0f
+ y--
+ }
+ }
+ else -> {
+ throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this")
+ }
+ }
+ //}
+ }
+ }
+
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
+
+ tx.render()
+ }
+ }
+ }
+
+
+ first = false
+ }
+}
diff --git a/src/com/persesgames/math/Matrix4.kt b/src/com/persesgames/math/Matrix4.kt
new file mode 100644
index 0000000..3cb4ed4
--- /dev/null
+++ b/src/com/persesgames/math/Matrix4.kt
@@ -0,0 +1,192 @@
+package com.persesgames.math
+
+import org.khronos.webgl.Float32Array
+
+/**
+ * User: rnentjes
+ * Date: 17-4-16
+ * Time: 15:43
+ */
+class Matrix4 {
+
+ internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ internal var temp = FloatArray(16)
+
+ private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ fun get(): FloatArray {
+ return matrix
+ }
+
+ fun getFloat32Array() = Float32Array(get().toTypedArray())
+
+ fun set(values: FloatArray) {
+ if (values.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ matrix = values
+ }
+
+ fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) {
+ val r = (angle / 180f * Math.PI).toFloat()
+ val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat()
+
+ matrix[0] = f / imageAspectRatio
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+
+ matrix[4] = 0.0f
+ matrix[5] = f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = -(far + near) / (far - near)
+ matrix[11] = -1.0f
+
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = -(2.0f * far * near) / (far - near)
+ matrix[15] = 0.0f
+ }
+
+ fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) {
+ matrix[0] = 2f / (right - left)
+ matrix[1] = 0f
+ matrix[2] = 0f
+ matrix[3] = 0f
+
+ matrix[4] = 0f
+ matrix[5] = 2f / (top - bottom)
+ matrix[6] = 0f
+ matrix[7] = 0f
+
+ matrix[8] = 0f
+ matrix[9] = 0f
+ matrix[10] = -2f / (far - near)
+ matrix[11] = 0f
+
+ matrix[12] = - (right + left) / (right - left)
+ matrix[13] = - (top + bottom) / (top - bottom)
+ matrix[14] = - (far + near) / (far - near)
+ matrix[15] = 1f
+ }
+
+ fun setToIdentity() {
+ matrix[0] = 1.0f
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+ matrix[4] = 0.0f
+ matrix[5] = 1.0f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = 1.0f
+ matrix[11] = 0.0f
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = 0.0f
+ matrix[15] = 1.0f
+ }
+
+ fun mul(other: Matrix4) {
+ mul(other.get())
+ }
+
+ protected fun mul(other: FloatArray) {
+ if (other.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12]
+ temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13]
+ temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14]
+ temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15]
+ temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12]
+ temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13]
+ temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14]
+ temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15]
+ temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12]
+ temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13]
+ temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14]
+ temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15]
+ temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12]
+ temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13]
+ temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14]
+ temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15]
+
+ matrix[0] = temp[0]
+ matrix[1] = temp[1]
+ matrix[2] = temp[2]
+ matrix[3] = temp[3]
+ matrix[4] = temp[4]
+ matrix[5] = temp[5]
+ matrix[6] = temp[6]
+ matrix[7] = temp[7]
+ matrix[8] = temp[8]
+ matrix[9] = temp[9]
+ matrix[10] = temp[10]
+ matrix[11] = temp[11]
+ matrix[12] = temp[12]
+ matrix[13] = temp[13]
+ matrix[14] = temp[14]
+ matrix[15] = temp[15]
+ }
+
+ fun translate(x: Float, y: Float, z: Float) {
+ translateMatrix[12] = x
+ translateMatrix[13] = y
+ translateMatrix[14] = z
+
+ mul(translateMatrix)
+ }
+
+ fun scale(x: Float, y: Float, z: Float) {
+ scaleMatrix[0] = x
+ scaleMatrix[5] = y
+ scaleMatrix[10] = z
+
+ mul(scaleMatrix)
+ }
+
+ fun rotateX(angle: Float) {
+ rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+ rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat()
+ rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateXMatrix)
+ }
+
+ fun rotateY(angle: Float) {
+ rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat()
+ rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateYMatrix)
+ }
+
+ fun rotateZ(angle: Float) {
+ rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat()
+ rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateZMatrix)
+ }
+}
diff --git a/src/com/persesgames/net/NetUtils.kt b/src/com/persesgames/net/NetUtils.kt
new file mode 100644
index 0000000..b59cbb3
--- /dev/null
+++ b/src/com/persesgames/net/NetUtils.kt
@@ -0,0 +1,18 @@
+package com.persesgames.net
+
+import org.w3c.xhr.XMLHttpRequest
+
+/**
+ * User: rnentjes
+ * Date: 30-7-16
+ * Time: 16:39
+ */
+
+fun getUrlAsString(url: String): String {
+ val req = XMLHttpRequest()
+
+ req.open("GET", url, false)
+ req.send(null)
+
+ return req.responseText
+}
diff --git a/src/com/persesgames/shader/ShaderProgram.kt b/src/com/persesgames/shader/ShaderProgram.kt
new file mode 100644
index 0000000..3c3aad5
--- /dev/null
+++ b/src/com/persesgames/shader/ShaderProgram.kt
@@ -0,0 +1,110 @@
+package com.persesgames.shader
+
+import org.khronos.webgl.*
+
+/**
+ * User: rnentjes
+ * Date: 17-4-16
+ * Time: 15:15
+ */
+
+class ShaderProgram(
+ val webgl: WebGLRenderingContext,
+ val drawType: Int,
+ vertexShaderSource: String,
+ fragmentShaderSource: String,
+ val vainfo: Array,
+ val setter: (program: ShaderProgram, data: T) -> Unit) {
+
+ var shaderProgram: WebGLProgram
+ var vertex: WebGLShader
+ var fragment: WebGLShader
+
+ var verticesBlockSize = 0
+ var drawLength = 0
+
+ init {
+ vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER)
+ fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER)
+
+ shaderProgram = webgl.createProgram() ?: throw IllegalStateException("Unable to request shader program from webgl context!")
+ webgl.attachShader(shaderProgram, vertex)
+ webgl.attachShader(shaderProgram, fragment)
+ webgl.linkProgram(shaderProgram)
+
+ if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) {
+ println(webgl.getProgramInfoLog(shaderProgram))
+ throw IllegalStateException("Unable to compile shader program!")
+ }
+
+ webgl.useProgram(shaderProgram)
+
+ this.verticesBlockSize = 0;
+
+ // set attribute locations...
+ for (info in vainfo.iterator()) {
+ info.location = webgl.getAttribLocation(shaderProgram, info.locationName)
+ info.offset = verticesBlockSize;
+
+ verticesBlockSize += info.numElements;
+ println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}");
+ }
+
+ when(drawType) {
+ WebGLRenderingContext.TRIANGLES -> {
+ drawLength = verticesBlockSize * 3
+ }
+ else -> {
+ drawLength = verticesBlockSize
+ }
+ }
+
+ println("verticesBlockSize $verticesBlockSize");
+
+ println("ShaderProgram constructor done");
+ }
+
+ private fun compileShader(source: String, type: Int): WebGLShader {
+ val result: WebGLShader
+
+ result = webgl.createShader(type) ?: throw IllegalStateException("Unable to request shader from webgl context!")
+ webgl.shaderSource(result, source)
+ webgl.compileShader(result)
+
+ if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) {
+ throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}")
+ }
+
+ return result
+ }
+
+ fun begin(attribBuffer: WebGLBuffer, userdata: T) {
+ webgl.useProgram(shaderProgram);
+ webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer);
+
+ // set attribute locations...
+ for (info in vainfo.iterator()) {
+ webgl.enableVertexAttribArray(info.location)
+ webgl.vertexAttribPointer(info.location, info.numElements, WebGLRenderingContext.FLOAT, false, verticesBlockSize * 4, info.offset * 4)
+ }
+
+ setter(this, userdata)
+ }
+
+ fun end() {
+ for (info in vainfo.iterator()) {
+ webgl.disableVertexAttribArray(info.location);
+ }
+ webgl.useProgram(null)
+ }
+
+ fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location);
+
+ fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location);
+
+ fun setUniform1f(location: String, value: Float) { webgl.uniform1f(getUniformLocation(location), value); }
+ fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); }
+ fun setUniform1i(location: String, value: Int) { webgl.uniform1i(getUniformLocation(location), value); }
+ fun setUniformMatrix4fv(location: String, value: Float32Array) { webgl.uniformMatrix4fv(getUniformLocation(location), false, value); }
+
+}
diff --git a/src/com/persesgames/shader/ShaderProgramMesh.kt b/src/com/persesgames/shader/ShaderProgramMesh.kt
new file mode 100644
index 0000000..f4c4dd5
--- /dev/null
+++ b/src/com/persesgames/shader/ShaderProgramMesh.kt
@@ -0,0 +1,71 @@
+package com.persesgames.shader
+
+import org.khronos.webgl.Float32Array
+import org.khronos.webgl.WebGLBuffer
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * User: rnentjes
+ * Date: 14-5-16
+ * Time: 11:57
+ */
+
+class VertextAttributeInfo(val locationName: String, val numElements: Int) {
+ var location = 0
+ var offset = 0
+}
+
+class ShaderProgramMesh(
+ val shaderProgram: ShaderProgram
+) {
+ val webgl = shaderProgram.webgl
+ val data: Float32Array
+ var currentIndex: Int = 0
+ val attribBuffer: WebGLBuffer
+ var counter = 0
+
+ init {
+ data = Float32Array(20000 - (20000 % shaderProgram.drawLength))
+
+ attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!")
+ webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer);
+ }
+
+ fun queue(vararg vertices: Float) {
+ queue(vertices as Array)
+ }
+
+ fun queue(vertices: Array) {
+ data.set(vertices, currentIndex)
+ currentIndex += vertices.size
+
+ if (currentIndex == data.length) {
+ println("Skipped draw call, to many values!")
+ currentIndex = 0
+ }
+ }
+
+ fun remaining() = data.length - currentIndex
+
+ fun bufferFull() = currentIndex == data.length
+
+ fun render(userdata: T) {
+ counter++
+ if (currentIndex > 0) {
+/* if (counter % 100 == 0) {
+ println("currentIndex=$currentIndex blockSize=${shaderProgram.verticesBlockSize} drawLength=${shaderProgram.drawLength} drawing=${(currentIndex / shaderProgram.verticesBlockSize).toInt()}")
+ }*/
+ if (currentIndex % shaderProgram.verticesBlockSize != 0) {
+ throw IllegalStateException("Number of vertices not a multiple of the attribute block size!")
+ }
+
+ shaderProgram.begin(attribBuffer, userdata)
+
+ webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW)
+ webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize).toInt())
+ currentIndex = 0
+
+ shaderProgram.end()
+ }
+ }
+}
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/settings.gradle b/settings.gradle
index 329f712..3181c92 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-rootProject.name = 'kotlin-webgl-test'
+rootProject.name = 'kudens'
diff --git a/src/com/persesgames/game/Game.kt b/src/com/persesgames/game/Game.kt
new file mode 100644
index 0000000..3abdd56
--- /dev/null
+++ b/src/com/persesgames/game/Game.kt
@@ -0,0 +1,155 @@
+package com.persesgames.game
+
+import com.persesgames.texture.Textures
+import org.khronos.webgl.WebGLRenderingContext
+import org.w3c.dom.CanvasRenderingContext2D
+import org.w3c.dom.HTMLCanvasElement
+import org.w3c.dom.HTMLElement
+import kotlin.browser.document
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+enum class DrawMode {
+ LINEAR,
+ NEAREST
+}
+
+class HTMLElements {
+ var container: HTMLElement
+ var webgl: WebGLRenderingContext
+ var canvas2d: CanvasRenderingContext2D
+
+ init {
+ container = document.createElement("div") as HTMLElement
+
+ val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement
+ val canvas = document.createElement("canvas") as HTMLCanvasElement
+
+ container.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
+ webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" )
+ canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" )
+
+ document.body!!.appendChild(container)
+ container.appendChild(webGlCanvas)
+ container.appendChild(canvas)
+
+ webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext
+ canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D
+ }
+}
+
+object Game {
+ var started = false
+ val view: View = View()
+ val html: HTMLElements by lazy { HTMLElements() }
+ var currentScreen: Screen = DefaultScreen()
+ var start = Date().getTime()
+ var currentTime = start
+ var currentDelta = 0f
+ var pause: Boolean = false
+
+ var fps = 0
+ var fpsCount = 0
+ var fpsCountTime = 0f
+
+ fun gl() = html.webgl
+
+ fun resize() {
+ val canvas = gl().canvas
+
+ // Check if the canvas is not the same size.
+ val windowWidth = window.innerWidth.toInt()
+ val windowHeight = window.innerHeight.toInt()
+
+ if (view.lastWindowWidth != windowWidth ||
+ view.lastWindowHeight != windowHeight) {
+ view.lastWindowWidth = windowWidth
+ view.lastWindowHeight = windowHeight
+ view.windowWidth = windowWidth
+ view.windowHeight = windowHeight
+
+ view.updateView()
+
+ val textCanvas = html.canvas2d.canvas
+
+ // Make the canvas the same size
+ canvas.width = view.width.toInt()
+ canvas.height = view.height.toInt()
+
+ textCanvas.width = view.width.toInt()
+ textCanvas.height = view.height.toInt()
+
+ gl().viewport(0, 0, view.width.toInt(), view.height.toInt())
+
+ val left = (windowWidth - view.windowWidth) / 2
+ val top = (windowHeight - view.windowHeight) / 2
+
+ canvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ textCanvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ }
+ }
+
+ fun start(startScreen: Screen) {
+ if (started) {
+ throw IllegalStateException("You can only start a game once!")
+ }
+
+ setScreen(startScreen)
+
+ // start game loop
+ started = true
+ gameLoop()
+ }
+
+ fun setScreen(screen: Screen) {
+ currentScreen.closeResources()
+
+ currentScreen = screen
+
+ currentScreen.loadResources()
+ }
+
+ fun gameLoop() {
+ if (!Textures.ready()) {
+ Game.gl().clearColor(1f, 1f, 1f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ } else {
+ resize()
+
+ if (!pause) {
+ html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble());
+
+ Game.gl().clearColor(0f, 0f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+
+ Game.gl().enable(WebGLRenderingContext.BLEND);
+ Game.gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA); //ONE_MINUS_DST_ALPHA);
+
+ val time = Date().getTime()
+ currentDelta = (time - currentTime) / 1000f
+ currentTime = time
+
+ val timeInSeconds = (currentTime - start) / 1000f
+
+ fpsCountTime += currentDelta
+ fpsCount++
+ while (fpsCountTime > 1f) {
+ fps = fpsCount
+ fpsCountTime -= 1f
+ fpsCount = 0
+ }
+
+ currentScreen.update(timeInSeconds, currentDelta);
+ currentScreen.render()
+ }
+ }
+
+ window.requestAnimationFrame {
+ gameLoop()
+ }
+ }
+
+}
diff --git a/src/com/persesgames/game/Screen.kt b/src/com/persesgames/game/Screen.kt
new file mode 100644
index 0000000..6fb558e
--- /dev/null
+++ b/src/com/persesgames/game/Screen.kt
@@ -0,0 +1,35 @@
+package com.persesgames.game
+
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+abstract class Screen {
+
+ open fun loadResources() {
+
+ }
+
+ open fun closeResources() {
+
+ }
+
+ abstract fun update(time: Float, delta: Float)
+
+ abstract fun render()
+
+}
+
+
+class DefaultScreen: Screen() {
+ override fun update(time: Float, delta: Float) {
+ }
+
+ override fun render() {
+ // show loading message?
+ Game.gl().clearColor(1f, 1f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/game/View.kt b/src/com/persesgames/game/View.kt
new file mode 100644
index 0000000..e5590e0
--- /dev/null
+++ b/src/com/persesgames/game/View.kt
@@ -0,0 +1,221 @@
+package com.persesgames.game
+
+import com.persesgames.math.Matrix4
+
+enum class ViewType {
+ PROJECTION,
+ WIDTH,
+ HEIGHT,
+ ABSOLUTE
+}
+
+class View(
+ var lastWindowWidth: Int = 2000,
+ var lastWindowHeight: Int = 1000,
+ var windowWidth: Int = 2000,
+ var windowHeight: Int = 1000,
+ var width: Float = 1024f,
+ var height: Float = 1024f,
+ var angle: Float = 60f,
+ var near: Float = -0.1f,
+ var far: Float = -100f,
+ var minAspectRatio: Float = 1f,
+ var maxAspectRatio: Float = 1f,
+ var leftOffset: Int = 0,
+ var bottomOffset: Int = 0,
+ var viewType: ViewType = ViewType.WIDTH,
+ var drawMode: DrawMode = DrawMode.LINEAR) {
+ var vMatrix = Matrix4()
+ var aspectRatio = 1f
+
+ init {
+ updateView()
+ }
+
+ fun requestFullscreen() {
+ println("Requesting fullscreen")
+ js("""
+ if (document.webkitFullscreenElement) {
+ document.webkitCancelFullScreen();
+ } else {
+ document.documentElement.webkitRequestFullScreen();
+ }
+ """)
+ //if (document.fullscreenEnabled) {
+ // println("fullscreen Enabled")
+ //Game.html.container.requestFullscreen()
+ //document.documentElement?.requestFullscreen()
+ //}
+ }
+
+ fun updateView() {
+ aspectRatio = windowWidth / windowHeight.toFloat()
+
+ if (aspectRatio < minAspectRatio) {
+ aspectRatio = minAspectRatio
+
+ windowHeight = (windowWidth / aspectRatio).toInt()
+ }
+
+ if (aspectRatio > maxAspectRatio) {
+ aspectRatio = maxAspectRatio
+
+ windowWidth = (windowHeight * aspectRatio).toInt()
+ }
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.WIDTH -> {
+ height = width / aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.HEIGHT -> {
+ width = height * aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.PROJECTION -> {
+ vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far);
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ //println("width: $width, height: $height")
+ }
+
+ fun screenToGameCoordX(screenX: Float): Float {
+ var result = screenX
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.HEIGHT -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun screenToGameCoordY(screenY: Float): Float {
+ var result = screenY
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.HEIGHT -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordX(gameX: Float): Float {
+ var result = gameX
+ val normalizedX = gameX + (width / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.HEIGHT -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordY(gameY: Float): Float {
+ var result = gameY
+ val normalizedY = gameY + (height / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.HEIGHT -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun setToWidth(width: Float) {
+ this.width = width
+ this.viewType = ViewType.WIDTH
+
+ updateView()
+ }
+
+ fun setToHeight(height: Float) {
+ this.height = height
+ this.viewType = ViewType.HEIGHT
+
+ updateView()
+ }
+
+ fun setProjection(angle: Float) {
+ this.angle = angle
+ this.viewType = ViewType.PROJECTION
+
+ updateView()
+ }
+
+ fun setNear(near: Float) {
+ this.near = near
+
+ updateView()
+ }
+
+ fun setFar(far: Float) {
+ this.far = far
+
+ updateView()
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/input/Keys.kt b/src/com/persesgames/input/Keys.kt
new file mode 100644
index 0000000..6705c67
--- /dev/null
+++ b/src/com/persesgames/input/Keys.kt
@@ -0,0 +1,141 @@
+package com.persesgames.input
+
+import com.persesgames.game.Game
+import org.w3c.dom.events.Event
+import org.w3c.dom.events.KeyboardEvent
+import org.w3c.dom.events.MouseEvent
+import java.util.*
+import kotlin.browser.document
+import kotlin.dom.on
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 12:18
+ */
+
+enum class KeyCode(val keyCode: Int) {
+ LEFT(37),
+ UP(38),
+ DOWN(40),
+ RIGHT(39),
+ SPACE(32),
+ MINUS(109),
+ PLUS(107),
+}
+
+interface InputProcessor {
+
+ fun keyPressed(charCode: Int)
+
+ fun keyDown(keyCode: Int)
+
+ fun keyUp(keyCode: Int)
+
+ fun pointerClick(pointer: Int, x: Float, y: Float)
+
+}
+
+open class EmptyInputProcessor : InputProcessor {
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ }
+
+ override fun keyDown(keyCode: Int) {
+ }
+
+ override fun keyPressed(charCode: Int) {
+ }
+
+ override fun keyUp(keyCode: Int) {
+ }
+
+
+}
+
+object Keys {
+
+ private val keys: MutableMap = HashMap();
+ private var inputProcesser: InputProcessor = EmptyInputProcessor()
+
+ init {
+ val body = document.body
+ if (body != null) {
+ body.on("keydown", true) {
+ Keys.keyDown(it)
+ }
+
+ body.on("keyup", true) {
+ Keys.keyUp(it)
+ }
+
+ body.on("keypress", true) {
+ Keys.keyPress(it)
+ }
+
+ body.on("click", true) {
+ Keys.mouseClick(it)
+ }
+
+ body.on("mousedown", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mouseup", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mousemove", true) {
+ Keys.mouseMove(it)
+ }
+ }
+ }
+
+ fun setInputProcessor(processor: InputProcessor) {
+ this.inputProcesser = processor
+ }
+
+ private fun keyDown(key: Event) {
+ if (key is KeyboardEvent) {
+ keys.put(key.keyCode, Date().getTime())
+
+ inputProcesser.keyDown(key.keyCode)
+ }
+ }
+
+ private fun keyUp(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyUp(key.keyCode)
+
+ keys.remove(key.keyCode)
+ }
+ }
+
+ private fun keyPress(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyPressed(key.charCode)
+ }
+ }
+
+ private fun mouseClick(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+ inputProcesser.pointerClick(event.button.toInt(), vx, vy)
+ }
+ }
+
+ private fun mouseMove(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+
+ }
+ }
+
+ fun isDown(keyCode: Int) = keys.containsKey(keyCode)
+
+ fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode)
+
+}
diff --git a/src/com/persesgames/map/Map.kt b/src/com/persesgames/map/Map.kt
new file mode 100644
index 0000000..b5d7bc8
--- /dev/null
+++ b/src/com/persesgames/map/Map.kt
@@ -0,0 +1,9 @@
+package com.persesgames.map
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+open class Map {
+
+}
diff --git a/src/com/persesgames/map/tiled/TiledMap.kt b/src/com/persesgames/map/tiled/TiledMap.kt
new file mode 100644
index 0000000..a84a5a3
--- /dev/null
+++ b/src/com/persesgames/map/tiled/TiledMap.kt
@@ -0,0 +1,211 @@
+package com.persesgames.map.tiled
+
+import com.persesgames.net.getUrlAsString
+import com.persesgames.texture.Texture
+import com.persesgames.texture.Textures
+import java.util.*
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+class MapData {
+ var version: Int = 1
+ var properties: MutableMap = HashMap()
+ var layers: Array? = null
+ var tilesets: Array? = null
+
+ var height: Int = 0
+ var width: Int = 0
+
+ var nextobjectid: Int = 0
+ var orientation: String = "orthogonal"
+ var renderorder: String = "right-down"
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+}
+
+class MapLayer {
+ var properties: MutableMap = HashMap()
+
+ var data: Array? = null
+ var encoding: String = ""
+ var x: Int = 0
+ var y: Int = 0
+ var width: Int = 0
+ var height: Int = 0
+ var name: String = ""
+ var opacity: Float = 1f
+ var type: String = ""
+ var visible: Boolean = true
+ var draworder: String = ""
+}
+
+class MapTileset {
+ var properties: MutableMap = HashMap()
+
+ var firstgid: Int = 0
+ var image: String = ""
+ var imageheight: Int = 0
+ var imagewidth: Int = 0
+ var margin: Int = 0
+ var name: String = ""
+ var spacing: Int = 0
+ var tilecount: Int = 0
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+ var tileproperties: MutableMap> = HashMap()
+}
+
+class TilesetIndex(
+ val texture: Texture?,
+ val tcLeft: Float,
+ val tcTop: Float,
+ val tcRight: Float,
+ val tcBottom: Float,
+ val scale: Float
+ ) {
+ constructor() : this(null, 0f, 0f, 0f, 0f, 0f)
+
+ fun render(x: Float, y: Float) {
+ texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+}
+
+class TiledMap(dir: String = "", url: String) {
+ val properties: Map = HashMap()
+ val data: MapData
+ val tileset: Array
+ val tiles: Array
+ var first = true
+ //var tilesetIndex: Array = Array(0, { TilesetIndex() })
+
+ init {
+ var tileDir = dir
+ if (!tileDir.isEmpty() && !tileDir.endsWith("/")) {
+ tileDir = tileDir + "/"
+ }
+
+ data = JSON.parse(getUrlAsString(tileDir + url))
+ println("map data is loaded")
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ tileset = Array(tilesets.size, { "" })
+ var maxGid = 0
+ for (index in 0..tilesets.size - 1) {
+ tileset[index] = tilesets[index].name
+ Textures.load(tilesets[index].name, tileDir + tilesets[index].image)
+ maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount)
+ }
+
+ tiles = Array(maxGid, { TilesetIndex() })
+ } else {
+ tileset = Array(0, { "" })
+ tiles = Array(0, { TilesetIndex() })
+ }
+
+ cacheTiles()
+ }
+
+ fun cacheTiles() {
+ if (!Textures.ready()) {
+ window.setTimeout({ cacheTiles() }, 10)
+ } else {
+ val tilesets = data.tilesets
+ var tcLeft = 0f
+ var tcTop = 0f
+ var tcRight = 0f
+ var tcBottom = 0f
+
+ if (tilesets != null) {
+
+
+ for (tileset in tilesets) {
+ val tilesHor = tileset.imagewidth / tileset.tilewidth
+ val tilesVer = tileset.imageheight / tileset.tileheight
+ val scale = (tileset.tilewidth / tileset.imagewidth.toFloat())
+
+ for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) {
+ val texture = Textures.get(tileset.name)
+
+ val gid = index - tileset.firstgid
+
+ val xi = gid % tilesHor
+ var yi = gid / tilesHor
+ yi = tilesVer - yi - 1
+ val tw = 1f / tilesHor.toFloat()
+ val th = 1f / tilesVer.toFloat()
+
+ val pixelW = 0.1f / tileset.tilewidth
+ val pixelH = 0.1f / tileset.tileheight
+
+ tcLeft = xi * tw
+ tcRight = tcLeft + tw
+
+ // switch up/down because of texture coord 0,0 in left bottom corner
+ tcBottom = yi * th
+ tcTop = tcBottom + th
+
+ tcLeft += pixelW
+ tcRight -= pixelW
+
+ tcBottom += pixelH
+ tcTop -= pixelH
+
+ tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+ }
+ }
+ }
+ }
+
+ fun drawTile(tile: Int, x: Float, y: Float) {
+ tiles[tile].render(x, y)
+ }
+
+ fun drawLayer(layerIndex: Int, xo: Float, yo: Float) {
+ var x = 0f
+ var y = 0f
+ val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)")
+ val layer = layers[layerIndex]
+
+ val layerData = layer.data
+ if (layerData != null) {
+ for (index in layerData.indices) {
+ // todo: determine if in view
+ // todo: determine tilewidth
+ //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) {
+ drawTile(layerData[index], xo + x * 128f, yo + y * 128f)
+
+ when (data.renderorder) {
+ "right-down" -> {
+ x++
+ if (x >= layer.width) {
+ x = 0f
+ y--
+ }
+ }
+ else -> {
+ throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this")
+ }
+ }
+ //}
+ }
+ }
+
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
+
+ tx.render()
+ }
+ }
+ }
+
+
+ first = false
+ }
+}
diff --git a/src/com/persesgames/math/Matrix4.kt b/src/com/persesgames/math/Matrix4.kt
new file mode 100644
index 0000000..3cb4ed4
--- /dev/null
+++ b/src/com/persesgames/math/Matrix4.kt
@@ -0,0 +1,192 @@
+package com.persesgames.math
+
+import org.khronos.webgl.Float32Array
+
+/**
+ * User: rnentjes
+ * Date: 17-4-16
+ * Time: 15:43
+ */
+class Matrix4 {
+
+ internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ internal var temp = FloatArray(16)
+
+ private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ fun get(): FloatArray {
+ return matrix
+ }
+
+ fun getFloat32Array() = Float32Array(get().toTypedArray())
+
+ fun set(values: FloatArray) {
+ if (values.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ matrix = values
+ }
+
+ fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) {
+ val r = (angle / 180f * Math.PI).toFloat()
+ val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat()
+
+ matrix[0] = f / imageAspectRatio
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+
+ matrix[4] = 0.0f
+ matrix[5] = f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = -(far + near) / (far - near)
+ matrix[11] = -1.0f
+
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = -(2.0f * far * near) / (far - near)
+ matrix[15] = 0.0f
+ }
+
+ fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) {
+ matrix[0] = 2f / (right - left)
+ matrix[1] = 0f
+ matrix[2] = 0f
+ matrix[3] = 0f
+
+ matrix[4] = 0f
+ matrix[5] = 2f / (top - bottom)
+ matrix[6] = 0f
+ matrix[7] = 0f
+
+ matrix[8] = 0f
+ matrix[9] = 0f
+ matrix[10] = -2f / (far - near)
+ matrix[11] = 0f
+
+ matrix[12] = - (right + left) / (right - left)
+ matrix[13] = - (top + bottom) / (top - bottom)
+ matrix[14] = - (far + near) / (far - near)
+ matrix[15] = 1f
+ }
+
+ fun setToIdentity() {
+ matrix[0] = 1.0f
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+ matrix[4] = 0.0f
+ matrix[5] = 1.0f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = 1.0f
+ matrix[11] = 0.0f
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = 0.0f
+ matrix[15] = 1.0f
+ }
+
+ fun mul(other: Matrix4) {
+ mul(other.get())
+ }
+
+ protected fun mul(other: FloatArray) {
+ if (other.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12]
+ temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13]
+ temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14]
+ temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15]
+ temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12]
+ temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13]
+ temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14]
+ temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15]
+ temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12]
+ temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13]
+ temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14]
+ temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15]
+ temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12]
+ temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13]
+ temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14]
+ temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15]
+
+ matrix[0] = temp[0]
+ matrix[1] = temp[1]
+ matrix[2] = temp[2]
+ matrix[3] = temp[3]
+ matrix[4] = temp[4]
+ matrix[5] = temp[5]
+ matrix[6] = temp[6]
+ matrix[7] = temp[7]
+ matrix[8] = temp[8]
+ matrix[9] = temp[9]
+ matrix[10] = temp[10]
+ matrix[11] = temp[11]
+ matrix[12] = temp[12]
+ matrix[13] = temp[13]
+ matrix[14] = temp[14]
+ matrix[15] = temp[15]
+ }
+
+ fun translate(x: Float, y: Float, z: Float) {
+ translateMatrix[12] = x
+ translateMatrix[13] = y
+ translateMatrix[14] = z
+
+ mul(translateMatrix)
+ }
+
+ fun scale(x: Float, y: Float, z: Float) {
+ scaleMatrix[0] = x
+ scaleMatrix[5] = y
+ scaleMatrix[10] = z
+
+ mul(scaleMatrix)
+ }
+
+ fun rotateX(angle: Float) {
+ rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+ rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat()
+ rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateXMatrix)
+ }
+
+ fun rotateY(angle: Float) {
+ rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat()
+ rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateYMatrix)
+ }
+
+ fun rotateZ(angle: Float) {
+ rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat()
+ rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateZMatrix)
+ }
+}
diff --git a/src/com/persesgames/net/NetUtils.kt b/src/com/persesgames/net/NetUtils.kt
new file mode 100644
index 0000000..b59cbb3
--- /dev/null
+++ b/src/com/persesgames/net/NetUtils.kt
@@ -0,0 +1,18 @@
+package com.persesgames.net
+
+import org.w3c.xhr.XMLHttpRequest
+
+/**
+ * User: rnentjes
+ * Date: 30-7-16
+ * Time: 16:39
+ */
+
+fun getUrlAsString(url: String): String {
+ val req = XMLHttpRequest()
+
+ req.open("GET", url, false)
+ req.send(null)
+
+ return req.responseText
+}
diff --git a/src/com/persesgames/shader/ShaderProgram.kt b/src/com/persesgames/shader/ShaderProgram.kt
new file mode 100644
index 0000000..3c3aad5
--- /dev/null
+++ b/src/com/persesgames/shader/ShaderProgram.kt
@@ -0,0 +1,110 @@
+package com.persesgames.shader
+
+import org.khronos.webgl.*
+
+/**
+ * User: rnentjes
+ * Date: 17-4-16
+ * Time: 15:15
+ */
+
+class ShaderProgram(
+ val webgl: WebGLRenderingContext,
+ val drawType: Int,
+ vertexShaderSource: String,
+ fragmentShaderSource: String,
+ val vainfo: Array,
+ val setter: (program: ShaderProgram, data: T) -> Unit) {
+
+ var shaderProgram: WebGLProgram
+ var vertex: WebGLShader
+ var fragment: WebGLShader
+
+ var verticesBlockSize = 0
+ var drawLength = 0
+
+ init {
+ vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER)
+ fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER)
+
+ shaderProgram = webgl.createProgram() ?: throw IllegalStateException("Unable to request shader program from webgl context!")
+ webgl.attachShader(shaderProgram, vertex)
+ webgl.attachShader(shaderProgram, fragment)
+ webgl.linkProgram(shaderProgram)
+
+ if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) {
+ println(webgl.getProgramInfoLog(shaderProgram))
+ throw IllegalStateException("Unable to compile shader program!")
+ }
+
+ webgl.useProgram(shaderProgram)
+
+ this.verticesBlockSize = 0;
+
+ // set attribute locations...
+ for (info in vainfo.iterator()) {
+ info.location = webgl.getAttribLocation(shaderProgram, info.locationName)
+ info.offset = verticesBlockSize;
+
+ verticesBlockSize += info.numElements;
+ println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}");
+ }
+
+ when(drawType) {
+ WebGLRenderingContext.TRIANGLES -> {
+ drawLength = verticesBlockSize * 3
+ }
+ else -> {
+ drawLength = verticesBlockSize
+ }
+ }
+
+ println("verticesBlockSize $verticesBlockSize");
+
+ println("ShaderProgram constructor done");
+ }
+
+ private fun compileShader(source: String, type: Int): WebGLShader {
+ val result: WebGLShader
+
+ result = webgl.createShader(type) ?: throw IllegalStateException("Unable to request shader from webgl context!")
+ webgl.shaderSource(result, source)
+ webgl.compileShader(result)
+
+ if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) {
+ throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}")
+ }
+
+ return result
+ }
+
+ fun begin(attribBuffer: WebGLBuffer, userdata: T) {
+ webgl.useProgram(shaderProgram);
+ webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer);
+
+ // set attribute locations...
+ for (info in vainfo.iterator()) {
+ webgl.enableVertexAttribArray(info.location)
+ webgl.vertexAttribPointer(info.location, info.numElements, WebGLRenderingContext.FLOAT, false, verticesBlockSize * 4, info.offset * 4)
+ }
+
+ setter(this, userdata)
+ }
+
+ fun end() {
+ for (info in vainfo.iterator()) {
+ webgl.disableVertexAttribArray(info.location);
+ }
+ webgl.useProgram(null)
+ }
+
+ fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location);
+
+ fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location);
+
+ fun setUniform1f(location: String, value: Float) { webgl.uniform1f(getUniformLocation(location), value); }
+ fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); }
+ fun setUniform1i(location: String, value: Int) { webgl.uniform1i(getUniformLocation(location), value); }
+ fun setUniformMatrix4fv(location: String, value: Float32Array) { webgl.uniformMatrix4fv(getUniformLocation(location), false, value); }
+
+}
diff --git a/src/com/persesgames/shader/ShaderProgramMesh.kt b/src/com/persesgames/shader/ShaderProgramMesh.kt
new file mode 100644
index 0000000..f4c4dd5
--- /dev/null
+++ b/src/com/persesgames/shader/ShaderProgramMesh.kt
@@ -0,0 +1,71 @@
+package com.persesgames.shader
+
+import org.khronos.webgl.Float32Array
+import org.khronos.webgl.WebGLBuffer
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * User: rnentjes
+ * Date: 14-5-16
+ * Time: 11:57
+ */
+
+class VertextAttributeInfo(val locationName: String, val numElements: Int) {
+ var location = 0
+ var offset = 0
+}
+
+class ShaderProgramMesh(
+ val shaderProgram: ShaderProgram
+) {
+ val webgl = shaderProgram.webgl
+ val data: Float32Array
+ var currentIndex: Int = 0
+ val attribBuffer: WebGLBuffer
+ var counter = 0
+
+ init {
+ data = Float32Array(20000 - (20000 % shaderProgram.drawLength))
+
+ attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!")
+ webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer);
+ }
+
+ fun queue(vararg vertices: Float) {
+ queue(vertices as Array)
+ }
+
+ fun queue(vertices: Array) {
+ data.set(vertices, currentIndex)
+ currentIndex += vertices.size
+
+ if (currentIndex == data.length) {
+ println("Skipped draw call, to many values!")
+ currentIndex = 0
+ }
+ }
+
+ fun remaining() = data.length - currentIndex
+
+ fun bufferFull() = currentIndex == data.length
+
+ fun render(userdata: T) {
+ counter++
+ if (currentIndex > 0) {
+/* if (counter % 100 == 0) {
+ println("currentIndex=$currentIndex blockSize=${shaderProgram.verticesBlockSize} drawLength=${shaderProgram.drawLength} drawing=${(currentIndex / shaderProgram.verticesBlockSize).toInt()}")
+ }*/
+ if (currentIndex % shaderProgram.verticesBlockSize != 0) {
+ throw IllegalStateException("Number of vertices not a multiple of the attribute block size!")
+ }
+
+ shaderProgram.begin(attribBuffer, userdata)
+
+ webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW)
+ webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize).toInt())
+ currentIndex = 0
+
+ shaderProgram.end()
+ }
+ }
+}
diff --git a/src/com/persesgames/shooter/Shooter.kt b/src/com/persesgames/shooter/Shooter.kt
deleted file mode 100644
index 864a1b6..0000000
--- a/src/com/persesgames/shooter/Shooter.kt
+++ /dev/null
@@ -1,206 +0,0 @@
-package com.persesgames.shooter
-
-import com.persesgames.game.DrawMode
-import com.persesgames.game.Game
-import com.persesgames.game.Screen
-import com.persesgames.input.EmptyInputProcessor
-import com.persesgames.input.KeyCode
-import com.persesgames.input.Keys
-import com.persesgames.map.tiled.TiledMap
-import com.persesgames.sound.Music
-import com.persesgames.sound.Sounds
-import com.persesgames.sprite.Sprite
-import com.persesgames.sprite.SpriteBatch
-import com.persesgames.text.Texts
-import com.persesgames.texture.Textures
-import org.w3c.dom.HTMLAudioElement
-import org.w3c.dom.HTMLInputElement
-import kotlin.browser.document
-
-/**
- * Created by rnentjes on 19-4-16.
- */
-
-class GameInputProcessor : EmptyInputProcessor() {
-
- override fun keyPressed(charCode: Int) {
- println("charCode: $charCode")
- if (charCode == 32) {
- Sounds.play("EXPLOSION", 0.5f)
- } else if (charCode == 'x'.toInt()) {
- Sounds.play("DROP", 0.75f)
- }
- }
-
- override fun pointerClick(pointer: Int, x: Float, y: Float) {
- println("POINTER $pointer -> ($x, $y)")
- }
-}
-
-var music: HTMLAudioElement? = null
-var showFPS: Boolean = true
-
-class WelcomeScreen : Screen() {
-
- override fun loadResources() {
- println("loading resource!")
-
- //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
-
- Textures.loadSpriteSheet("images/data-0.json")
-
- Keys.setInputProcessor(GameInputProcessor())
- }
-
- override fun update(time: Float, delta: Float) { }
-
- override fun render() {
-
- if (showFPS) {
- Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
- }
- }
-}
-
-class GameScreen : Screen() {
- val map = TiledMap("maps", "level_1_01.json")
-
- var sprites = SpriteBatch()
- var x = 0f
- var y = 15500f
- var sprite = Sprite("SHIP")
- var numberOfSprites: Int = 5000
- var time: Float = 0f
-
- override fun loadResources() {
- Textures.load("SHIP", "images/ship2.png")
-
- Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
- Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
-
- music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
-
- Keys.setInputProcessor(GameInputProcessor())
-
- println("width: ${map.data.width}")
- println("height: ${map.data.height}")
- println("layers: ${map.data.layers?.size}")
-
- val layers = map.data.layers
- if (layers != null) {
- println("layer0: ${layers[0].name}")
- }
- val tilesets = map.data.tilesets
- if (tilesets != null) {
- println("tilesets ${tilesets.size}")
- println("tileset0: ${tilesets[0].name}")
- }
- }
-
- override fun update(time: Float, delta: Float) {
- this.time = time
- val speed = 1500f // units per second
-
- if (Keys.isDown(KeyCode.LEFT)) {
- x -= delta * speed
- println("x=$x")
- }
-
- if (Keys.isDown(KeyCode.RIGHT)) {
- x += delta * speed
- println("x=$x")
- }
-
- if (Keys.isDown(KeyCode.UP)) {
- y += delta * speed
- println("y=$y")
- }
-
- if (Keys.isDown(KeyCode.DOWN)) {
- y -= delta * speed
- println("y=$y")
- }
-
- if (Keys.isDown(KeyCode.MINUS)) {
- if (numberOfSprites > 25) {
- numberOfSprites = (numberOfSprites * 0.9f).toInt()
- }
- }
-
- if (Keys.isDown(KeyCode.PLUS)) {
- numberOfSprites = (numberOfSprites * 1.1f).toInt()
- }
- }
-
- override fun render() {
- var r = 0f
- var d = 0f
- var x = 0f
- var y = 0f
-
- map.drawLayer(1, this.x, this.y)
- map.drawLayer(2, this.x, this.y)
-
- val time = this.time / 10f
- for (index in 0..numberOfSprites) {
- r = index * 0.05f
- d = index * 2.13f
- x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
- y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
-
- sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
- }
-
- sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
-
- sprites.render()
-
- Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
-
- if (showFPS) {
- Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
- Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
- }
- }
-
-}
-
-fun main(args: Array) {
- Game.view.setToHeight(1000f)
- Game.view.drawMode = DrawMode.LINEAR
-
- Game.view.minAspectRatio = 0.9f
- Game.view.maxAspectRatio = 1.5f
-
- Game.start(WelcomeScreen())
-}
-
-fun changeMusic(it: HTMLInputElement) {
- val mus = music
-
- if (mus != null) {
- if (it.checked) {
- mus.volume = 0.5
- } else {
- mus.volume = 0.0
- }
- }
-}
-
-fun showFPS(it: HTMLInputElement) {
- showFPS = it.checked
-}
-
-fun pause(it: HTMLInputElement) {
- Game.pause = it.checked
-}
-
-fun playGame() {
- document.getElementById("menu")?.setAttribute("style", "display: none;")
-
- Game.setScreen(GameScreen())
-}
-
-fun fullscreen() {
- Game.view.requestFullscreen()
-}
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/settings.gradle b/settings.gradle
index 329f712..3181c92 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-rootProject.name = 'kotlin-webgl-test'
+rootProject.name = 'kudens'
diff --git a/src/com/persesgames/game/Game.kt b/src/com/persesgames/game/Game.kt
new file mode 100644
index 0000000..3abdd56
--- /dev/null
+++ b/src/com/persesgames/game/Game.kt
@@ -0,0 +1,155 @@
+package com.persesgames.game
+
+import com.persesgames.texture.Textures
+import org.khronos.webgl.WebGLRenderingContext
+import org.w3c.dom.CanvasRenderingContext2D
+import org.w3c.dom.HTMLCanvasElement
+import org.w3c.dom.HTMLElement
+import kotlin.browser.document
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+enum class DrawMode {
+ LINEAR,
+ NEAREST
+}
+
+class HTMLElements {
+ var container: HTMLElement
+ var webgl: WebGLRenderingContext
+ var canvas2d: CanvasRenderingContext2D
+
+ init {
+ container = document.createElement("div") as HTMLElement
+
+ val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement
+ val canvas = document.createElement("canvas") as HTMLCanvasElement
+
+ container.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
+ webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" )
+ canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" )
+
+ document.body!!.appendChild(container)
+ container.appendChild(webGlCanvas)
+ container.appendChild(canvas)
+
+ webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext
+ canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D
+ }
+}
+
+object Game {
+ var started = false
+ val view: View = View()
+ val html: HTMLElements by lazy { HTMLElements() }
+ var currentScreen: Screen = DefaultScreen()
+ var start = Date().getTime()
+ var currentTime = start
+ var currentDelta = 0f
+ var pause: Boolean = false
+
+ var fps = 0
+ var fpsCount = 0
+ var fpsCountTime = 0f
+
+ fun gl() = html.webgl
+
+ fun resize() {
+ val canvas = gl().canvas
+
+ // Check if the canvas is not the same size.
+ val windowWidth = window.innerWidth.toInt()
+ val windowHeight = window.innerHeight.toInt()
+
+ if (view.lastWindowWidth != windowWidth ||
+ view.lastWindowHeight != windowHeight) {
+ view.lastWindowWidth = windowWidth
+ view.lastWindowHeight = windowHeight
+ view.windowWidth = windowWidth
+ view.windowHeight = windowHeight
+
+ view.updateView()
+
+ val textCanvas = html.canvas2d.canvas
+
+ // Make the canvas the same size
+ canvas.width = view.width.toInt()
+ canvas.height = view.height.toInt()
+
+ textCanvas.width = view.width.toInt()
+ textCanvas.height = view.height.toInt()
+
+ gl().viewport(0, 0, view.width.toInt(), view.height.toInt())
+
+ val left = (windowWidth - view.windowWidth) / 2
+ val top = (windowHeight - view.windowHeight) / 2
+
+ canvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ textCanvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ }
+ }
+
+ fun start(startScreen: Screen) {
+ if (started) {
+ throw IllegalStateException("You can only start a game once!")
+ }
+
+ setScreen(startScreen)
+
+ // start game loop
+ started = true
+ gameLoop()
+ }
+
+ fun setScreen(screen: Screen) {
+ currentScreen.closeResources()
+
+ currentScreen = screen
+
+ currentScreen.loadResources()
+ }
+
+ fun gameLoop() {
+ if (!Textures.ready()) {
+ Game.gl().clearColor(1f, 1f, 1f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ } else {
+ resize()
+
+ if (!pause) {
+ html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble());
+
+ Game.gl().clearColor(0f, 0f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+
+ Game.gl().enable(WebGLRenderingContext.BLEND);
+ Game.gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA); //ONE_MINUS_DST_ALPHA);
+
+ val time = Date().getTime()
+ currentDelta = (time - currentTime) / 1000f
+ currentTime = time
+
+ val timeInSeconds = (currentTime - start) / 1000f
+
+ fpsCountTime += currentDelta
+ fpsCount++
+ while (fpsCountTime > 1f) {
+ fps = fpsCount
+ fpsCountTime -= 1f
+ fpsCount = 0
+ }
+
+ currentScreen.update(timeInSeconds, currentDelta);
+ currentScreen.render()
+ }
+ }
+
+ window.requestAnimationFrame {
+ gameLoop()
+ }
+ }
+
+}
diff --git a/src/com/persesgames/game/Screen.kt b/src/com/persesgames/game/Screen.kt
new file mode 100644
index 0000000..6fb558e
--- /dev/null
+++ b/src/com/persesgames/game/Screen.kt
@@ -0,0 +1,35 @@
+package com.persesgames.game
+
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+abstract class Screen {
+
+ open fun loadResources() {
+
+ }
+
+ open fun closeResources() {
+
+ }
+
+ abstract fun update(time: Float, delta: Float)
+
+ abstract fun render()
+
+}
+
+
+class DefaultScreen: Screen() {
+ override fun update(time: Float, delta: Float) {
+ }
+
+ override fun render() {
+ // show loading message?
+ Game.gl().clearColor(1f, 1f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/game/View.kt b/src/com/persesgames/game/View.kt
new file mode 100644
index 0000000..e5590e0
--- /dev/null
+++ b/src/com/persesgames/game/View.kt
@@ -0,0 +1,221 @@
+package com.persesgames.game
+
+import com.persesgames.math.Matrix4
+
+enum class ViewType {
+ PROJECTION,
+ WIDTH,
+ HEIGHT,
+ ABSOLUTE
+}
+
+class View(
+ var lastWindowWidth: Int = 2000,
+ var lastWindowHeight: Int = 1000,
+ var windowWidth: Int = 2000,
+ var windowHeight: Int = 1000,
+ var width: Float = 1024f,
+ var height: Float = 1024f,
+ var angle: Float = 60f,
+ var near: Float = -0.1f,
+ var far: Float = -100f,
+ var minAspectRatio: Float = 1f,
+ var maxAspectRatio: Float = 1f,
+ var leftOffset: Int = 0,
+ var bottomOffset: Int = 0,
+ var viewType: ViewType = ViewType.WIDTH,
+ var drawMode: DrawMode = DrawMode.LINEAR) {
+ var vMatrix = Matrix4()
+ var aspectRatio = 1f
+
+ init {
+ updateView()
+ }
+
+ fun requestFullscreen() {
+ println("Requesting fullscreen")
+ js("""
+ if (document.webkitFullscreenElement) {
+ document.webkitCancelFullScreen();
+ } else {
+ document.documentElement.webkitRequestFullScreen();
+ }
+ """)
+ //if (document.fullscreenEnabled) {
+ // println("fullscreen Enabled")
+ //Game.html.container.requestFullscreen()
+ //document.documentElement?.requestFullscreen()
+ //}
+ }
+
+ fun updateView() {
+ aspectRatio = windowWidth / windowHeight.toFloat()
+
+ if (aspectRatio < minAspectRatio) {
+ aspectRatio = minAspectRatio
+
+ windowHeight = (windowWidth / aspectRatio).toInt()
+ }
+
+ if (aspectRatio > maxAspectRatio) {
+ aspectRatio = maxAspectRatio
+
+ windowWidth = (windowHeight * aspectRatio).toInt()
+ }
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.WIDTH -> {
+ height = width / aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.HEIGHT -> {
+ width = height * aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.PROJECTION -> {
+ vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far);
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ //println("width: $width, height: $height")
+ }
+
+ fun screenToGameCoordX(screenX: Float): Float {
+ var result = screenX
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.HEIGHT -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun screenToGameCoordY(screenY: Float): Float {
+ var result = screenY
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.HEIGHT -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordX(gameX: Float): Float {
+ var result = gameX
+ val normalizedX = gameX + (width / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.HEIGHT -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordY(gameY: Float): Float {
+ var result = gameY
+ val normalizedY = gameY + (height / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.HEIGHT -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun setToWidth(width: Float) {
+ this.width = width
+ this.viewType = ViewType.WIDTH
+
+ updateView()
+ }
+
+ fun setToHeight(height: Float) {
+ this.height = height
+ this.viewType = ViewType.HEIGHT
+
+ updateView()
+ }
+
+ fun setProjection(angle: Float) {
+ this.angle = angle
+ this.viewType = ViewType.PROJECTION
+
+ updateView()
+ }
+
+ fun setNear(near: Float) {
+ this.near = near
+
+ updateView()
+ }
+
+ fun setFar(far: Float) {
+ this.far = far
+
+ updateView()
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/input/Keys.kt b/src/com/persesgames/input/Keys.kt
new file mode 100644
index 0000000..6705c67
--- /dev/null
+++ b/src/com/persesgames/input/Keys.kt
@@ -0,0 +1,141 @@
+package com.persesgames.input
+
+import com.persesgames.game.Game
+import org.w3c.dom.events.Event
+import org.w3c.dom.events.KeyboardEvent
+import org.w3c.dom.events.MouseEvent
+import java.util.*
+import kotlin.browser.document
+import kotlin.dom.on
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 12:18
+ */
+
+enum class KeyCode(val keyCode: Int) {
+ LEFT(37),
+ UP(38),
+ DOWN(40),
+ RIGHT(39),
+ SPACE(32),
+ MINUS(109),
+ PLUS(107),
+}
+
+interface InputProcessor {
+
+ fun keyPressed(charCode: Int)
+
+ fun keyDown(keyCode: Int)
+
+ fun keyUp(keyCode: Int)
+
+ fun pointerClick(pointer: Int, x: Float, y: Float)
+
+}
+
+open class EmptyInputProcessor : InputProcessor {
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ }
+
+ override fun keyDown(keyCode: Int) {
+ }
+
+ override fun keyPressed(charCode: Int) {
+ }
+
+ override fun keyUp(keyCode: Int) {
+ }
+
+
+}
+
+object Keys {
+
+ private val keys: MutableMap = HashMap();
+ private var inputProcesser: InputProcessor = EmptyInputProcessor()
+
+ init {
+ val body = document.body
+ if (body != null) {
+ body.on("keydown", true) {
+ Keys.keyDown(it)
+ }
+
+ body.on("keyup", true) {
+ Keys.keyUp(it)
+ }
+
+ body.on("keypress", true) {
+ Keys.keyPress(it)
+ }
+
+ body.on("click", true) {
+ Keys.mouseClick(it)
+ }
+
+ body.on("mousedown", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mouseup", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mousemove", true) {
+ Keys.mouseMove(it)
+ }
+ }
+ }
+
+ fun setInputProcessor(processor: InputProcessor) {
+ this.inputProcesser = processor
+ }
+
+ private fun keyDown(key: Event) {
+ if (key is KeyboardEvent) {
+ keys.put(key.keyCode, Date().getTime())
+
+ inputProcesser.keyDown(key.keyCode)
+ }
+ }
+
+ private fun keyUp(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyUp(key.keyCode)
+
+ keys.remove(key.keyCode)
+ }
+ }
+
+ private fun keyPress(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyPressed(key.charCode)
+ }
+ }
+
+ private fun mouseClick(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+ inputProcesser.pointerClick(event.button.toInt(), vx, vy)
+ }
+ }
+
+ private fun mouseMove(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+
+ }
+ }
+
+ fun isDown(keyCode: Int) = keys.containsKey(keyCode)
+
+ fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode)
+
+}
diff --git a/src/com/persesgames/map/Map.kt b/src/com/persesgames/map/Map.kt
new file mode 100644
index 0000000..b5d7bc8
--- /dev/null
+++ b/src/com/persesgames/map/Map.kt
@@ -0,0 +1,9 @@
+package com.persesgames.map
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+open class Map {
+
+}
diff --git a/src/com/persesgames/map/tiled/TiledMap.kt b/src/com/persesgames/map/tiled/TiledMap.kt
new file mode 100644
index 0000000..a84a5a3
--- /dev/null
+++ b/src/com/persesgames/map/tiled/TiledMap.kt
@@ -0,0 +1,211 @@
+package com.persesgames.map.tiled
+
+import com.persesgames.net.getUrlAsString
+import com.persesgames.texture.Texture
+import com.persesgames.texture.Textures
+import java.util.*
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+class MapData {
+ var version: Int = 1
+ var properties: MutableMap = HashMap()
+ var layers: Array? = null
+ var tilesets: Array? = null
+
+ var height: Int = 0
+ var width: Int = 0
+
+ var nextobjectid: Int = 0
+ var orientation: String = "orthogonal"
+ var renderorder: String = "right-down"
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+}
+
+class MapLayer {
+ var properties: MutableMap = HashMap()
+
+ var data: Array? = null
+ var encoding: String = ""
+ var x: Int = 0
+ var y: Int = 0
+ var width: Int = 0
+ var height: Int = 0
+ var name: String = ""
+ var opacity: Float = 1f
+ var type: String = ""
+ var visible: Boolean = true
+ var draworder: String = ""
+}
+
+class MapTileset {
+ var properties: MutableMap = HashMap()
+
+ var firstgid: Int = 0
+ var image: String = ""
+ var imageheight: Int = 0
+ var imagewidth: Int = 0
+ var margin: Int = 0
+ var name: String = ""
+ var spacing: Int = 0
+ var tilecount: Int = 0
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+ var tileproperties: MutableMap> = HashMap()
+}
+
+class TilesetIndex(
+ val texture: Texture?,
+ val tcLeft: Float,
+ val tcTop: Float,
+ val tcRight: Float,
+ val tcBottom: Float,
+ val scale: Float
+ ) {
+ constructor() : this(null, 0f, 0f, 0f, 0f, 0f)
+
+ fun render(x: Float, y: Float) {
+ texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+}
+
+class TiledMap(dir: String = "", url: String) {
+ val properties: Map = HashMap()
+ val data: MapData
+ val tileset: Array
+ val tiles: Array
+ var first = true
+ //var tilesetIndex: Array = Array(0, { TilesetIndex() })
+
+ init {
+ var tileDir = dir
+ if (!tileDir.isEmpty() && !tileDir.endsWith("/")) {
+ tileDir = tileDir + "/"
+ }
+
+ data = JSON.parse(getUrlAsString(tileDir + url))
+ println("map data is loaded")
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ tileset = Array(tilesets.size, { "" })
+ var maxGid = 0
+ for (index in 0..tilesets.size - 1) {
+ tileset[index] = tilesets[index].name
+ Textures.load(tilesets[index].name, tileDir + tilesets[index].image)
+ maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount)
+ }
+
+ tiles = Array(maxGid, { TilesetIndex() })
+ } else {
+ tileset = Array(0, { "" })
+ tiles = Array(0, { TilesetIndex() })
+ }
+
+ cacheTiles()
+ }
+
+ fun cacheTiles() {
+ if (!Textures.ready()) {
+ window.setTimeout({ cacheTiles() }, 10)
+ } else {
+ val tilesets = data.tilesets
+ var tcLeft = 0f
+ var tcTop = 0f
+ var tcRight = 0f
+ var tcBottom = 0f
+
+ if (tilesets != null) {
+
+
+ for (tileset in tilesets) {
+ val tilesHor = tileset.imagewidth / tileset.tilewidth
+ val tilesVer = tileset.imageheight / tileset.tileheight
+ val scale = (tileset.tilewidth / tileset.imagewidth.toFloat())
+
+ for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) {
+ val texture = Textures.get(tileset.name)
+
+ val gid = index - tileset.firstgid
+
+ val xi = gid % tilesHor
+ var yi = gid / tilesHor
+ yi = tilesVer - yi - 1
+ val tw = 1f / tilesHor.toFloat()
+ val th = 1f / tilesVer.toFloat()
+
+ val pixelW = 0.1f / tileset.tilewidth
+ val pixelH = 0.1f / tileset.tileheight
+
+ tcLeft = xi * tw
+ tcRight = tcLeft + tw
+
+ // switch up/down because of texture coord 0,0 in left bottom corner
+ tcBottom = yi * th
+ tcTop = tcBottom + th
+
+ tcLeft += pixelW
+ tcRight -= pixelW
+
+ tcBottom += pixelH
+ tcTop -= pixelH
+
+ tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+ }
+ }
+ }
+ }
+
+ fun drawTile(tile: Int, x: Float, y: Float) {
+ tiles[tile].render(x, y)
+ }
+
+ fun drawLayer(layerIndex: Int, xo: Float, yo: Float) {
+ var x = 0f
+ var y = 0f
+ val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)")
+ val layer = layers[layerIndex]
+
+ val layerData = layer.data
+ if (layerData != null) {
+ for (index in layerData.indices) {
+ // todo: determine if in view
+ // todo: determine tilewidth
+ //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) {
+ drawTile(layerData[index], xo + x * 128f, yo + y * 128f)
+
+ when (data.renderorder) {
+ "right-down" -> {
+ x++
+ if (x >= layer.width) {
+ x = 0f
+ y--
+ }
+ }
+ else -> {
+ throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this")
+ }
+ }
+ //}
+ }
+ }
+
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
+
+ tx.render()
+ }
+ }
+ }
+
+
+ first = false
+ }
+}
diff --git a/src/com/persesgames/math/Matrix4.kt b/src/com/persesgames/math/Matrix4.kt
new file mode 100644
index 0000000..3cb4ed4
--- /dev/null
+++ b/src/com/persesgames/math/Matrix4.kt
@@ -0,0 +1,192 @@
+package com.persesgames.math
+
+import org.khronos.webgl.Float32Array
+
+/**
+ * User: rnentjes
+ * Date: 17-4-16
+ * Time: 15:43
+ */
+class Matrix4 {
+
+ internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ internal var temp = FloatArray(16)
+
+ private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ fun get(): FloatArray {
+ return matrix
+ }
+
+ fun getFloat32Array() = Float32Array(get().toTypedArray())
+
+ fun set(values: FloatArray) {
+ if (values.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ matrix = values
+ }
+
+ fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) {
+ val r = (angle / 180f * Math.PI).toFloat()
+ val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat()
+
+ matrix[0] = f / imageAspectRatio
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+
+ matrix[4] = 0.0f
+ matrix[5] = f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = -(far + near) / (far - near)
+ matrix[11] = -1.0f
+
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = -(2.0f * far * near) / (far - near)
+ matrix[15] = 0.0f
+ }
+
+ fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) {
+ matrix[0] = 2f / (right - left)
+ matrix[1] = 0f
+ matrix[2] = 0f
+ matrix[3] = 0f
+
+ matrix[4] = 0f
+ matrix[5] = 2f / (top - bottom)
+ matrix[6] = 0f
+ matrix[7] = 0f
+
+ matrix[8] = 0f
+ matrix[9] = 0f
+ matrix[10] = -2f / (far - near)
+ matrix[11] = 0f
+
+ matrix[12] = - (right + left) / (right - left)
+ matrix[13] = - (top + bottom) / (top - bottom)
+ matrix[14] = - (far + near) / (far - near)
+ matrix[15] = 1f
+ }
+
+ fun setToIdentity() {
+ matrix[0] = 1.0f
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+ matrix[4] = 0.0f
+ matrix[5] = 1.0f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = 1.0f
+ matrix[11] = 0.0f
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = 0.0f
+ matrix[15] = 1.0f
+ }
+
+ fun mul(other: Matrix4) {
+ mul(other.get())
+ }
+
+ protected fun mul(other: FloatArray) {
+ if (other.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12]
+ temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13]
+ temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14]
+ temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15]
+ temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12]
+ temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13]
+ temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14]
+ temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15]
+ temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12]
+ temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13]
+ temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14]
+ temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15]
+ temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12]
+ temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13]
+ temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14]
+ temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15]
+
+ matrix[0] = temp[0]
+ matrix[1] = temp[1]
+ matrix[2] = temp[2]
+ matrix[3] = temp[3]
+ matrix[4] = temp[4]
+ matrix[5] = temp[5]
+ matrix[6] = temp[6]
+ matrix[7] = temp[7]
+ matrix[8] = temp[8]
+ matrix[9] = temp[9]
+ matrix[10] = temp[10]
+ matrix[11] = temp[11]
+ matrix[12] = temp[12]
+ matrix[13] = temp[13]
+ matrix[14] = temp[14]
+ matrix[15] = temp[15]
+ }
+
+ fun translate(x: Float, y: Float, z: Float) {
+ translateMatrix[12] = x
+ translateMatrix[13] = y
+ translateMatrix[14] = z
+
+ mul(translateMatrix)
+ }
+
+ fun scale(x: Float, y: Float, z: Float) {
+ scaleMatrix[0] = x
+ scaleMatrix[5] = y
+ scaleMatrix[10] = z
+
+ mul(scaleMatrix)
+ }
+
+ fun rotateX(angle: Float) {
+ rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+ rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat()
+ rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateXMatrix)
+ }
+
+ fun rotateY(angle: Float) {
+ rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat()
+ rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateYMatrix)
+ }
+
+ fun rotateZ(angle: Float) {
+ rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat()
+ rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateZMatrix)
+ }
+}
diff --git a/src/com/persesgames/net/NetUtils.kt b/src/com/persesgames/net/NetUtils.kt
new file mode 100644
index 0000000..b59cbb3
--- /dev/null
+++ b/src/com/persesgames/net/NetUtils.kt
@@ -0,0 +1,18 @@
+package com.persesgames.net
+
+import org.w3c.xhr.XMLHttpRequest
+
+/**
+ * User: rnentjes
+ * Date: 30-7-16
+ * Time: 16:39
+ */
+
+fun getUrlAsString(url: String): String {
+ val req = XMLHttpRequest()
+
+ req.open("GET", url, false)
+ req.send(null)
+
+ return req.responseText
+}
diff --git a/src/com/persesgames/shader/ShaderProgram.kt b/src/com/persesgames/shader/ShaderProgram.kt
new file mode 100644
index 0000000..3c3aad5
--- /dev/null
+++ b/src/com/persesgames/shader/ShaderProgram.kt
@@ -0,0 +1,110 @@
+package com.persesgames.shader
+
+import org.khronos.webgl.*
+
+/**
+ * User: rnentjes
+ * Date: 17-4-16
+ * Time: 15:15
+ */
+
+class ShaderProgram(
+ val webgl: WebGLRenderingContext,
+ val drawType: Int,
+ vertexShaderSource: String,
+ fragmentShaderSource: String,
+ val vainfo: Array,
+ val setter: (program: ShaderProgram, data: T) -> Unit) {
+
+ var shaderProgram: WebGLProgram
+ var vertex: WebGLShader
+ var fragment: WebGLShader
+
+ var verticesBlockSize = 0
+ var drawLength = 0
+
+ init {
+ vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER)
+ fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER)
+
+ shaderProgram = webgl.createProgram() ?: throw IllegalStateException("Unable to request shader program from webgl context!")
+ webgl.attachShader(shaderProgram, vertex)
+ webgl.attachShader(shaderProgram, fragment)
+ webgl.linkProgram(shaderProgram)
+
+ if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) {
+ println(webgl.getProgramInfoLog(shaderProgram))
+ throw IllegalStateException("Unable to compile shader program!")
+ }
+
+ webgl.useProgram(shaderProgram)
+
+ this.verticesBlockSize = 0;
+
+ // set attribute locations...
+ for (info in vainfo.iterator()) {
+ info.location = webgl.getAttribLocation(shaderProgram, info.locationName)
+ info.offset = verticesBlockSize;
+
+ verticesBlockSize += info.numElements;
+ println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}");
+ }
+
+ when(drawType) {
+ WebGLRenderingContext.TRIANGLES -> {
+ drawLength = verticesBlockSize * 3
+ }
+ else -> {
+ drawLength = verticesBlockSize
+ }
+ }
+
+ println("verticesBlockSize $verticesBlockSize");
+
+ println("ShaderProgram constructor done");
+ }
+
+ private fun compileShader(source: String, type: Int): WebGLShader {
+ val result: WebGLShader
+
+ result = webgl.createShader(type) ?: throw IllegalStateException("Unable to request shader from webgl context!")
+ webgl.shaderSource(result, source)
+ webgl.compileShader(result)
+
+ if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) {
+ throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}")
+ }
+
+ return result
+ }
+
+ fun begin(attribBuffer: WebGLBuffer, userdata: T) {
+ webgl.useProgram(shaderProgram);
+ webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer);
+
+ // set attribute locations...
+ for (info in vainfo.iterator()) {
+ webgl.enableVertexAttribArray(info.location)
+ webgl.vertexAttribPointer(info.location, info.numElements, WebGLRenderingContext.FLOAT, false, verticesBlockSize * 4, info.offset * 4)
+ }
+
+ setter(this, userdata)
+ }
+
+ fun end() {
+ for (info in vainfo.iterator()) {
+ webgl.disableVertexAttribArray(info.location);
+ }
+ webgl.useProgram(null)
+ }
+
+ fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location);
+
+ fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location);
+
+ fun setUniform1f(location: String, value: Float) { webgl.uniform1f(getUniformLocation(location), value); }
+ fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); }
+ fun setUniform1i(location: String, value: Int) { webgl.uniform1i(getUniformLocation(location), value); }
+ fun setUniformMatrix4fv(location: String, value: Float32Array) { webgl.uniformMatrix4fv(getUniformLocation(location), false, value); }
+
+}
diff --git a/src/com/persesgames/shader/ShaderProgramMesh.kt b/src/com/persesgames/shader/ShaderProgramMesh.kt
new file mode 100644
index 0000000..f4c4dd5
--- /dev/null
+++ b/src/com/persesgames/shader/ShaderProgramMesh.kt
@@ -0,0 +1,71 @@
+package com.persesgames.shader
+
+import org.khronos.webgl.Float32Array
+import org.khronos.webgl.WebGLBuffer
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * User: rnentjes
+ * Date: 14-5-16
+ * Time: 11:57
+ */
+
+class VertextAttributeInfo(val locationName: String, val numElements: Int) {
+ var location = 0
+ var offset = 0
+}
+
+class ShaderProgramMesh(
+ val shaderProgram: ShaderProgram
+) {
+ val webgl = shaderProgram.webgl
+ val data: Float32Array
+ var currentIndex: Int = 0
+ val attribBuffer: WebGLBuffer
+ var counter = 0
+
+ init {
+ data = Float32Array(20000 - (20000 % shaderProgram.drawLength))
+
+ attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!")
+ webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer);
+ }
+
+ fun queue(vararg vertices: Float) {
+ queue(vertices as Array)
+ }
+
+ fun queue(vertices: Array) {
+ data.set(vertices, currentIndex)
+ currentIndex += vertices.size
+
+ if (currentIndex == data.length) {
+ println("Skipped draw call, to many values!")
+ currentIndex = 0
+ }
+ }
+
+ fun remaining() = data.length - currentIndex
+
+ fun bufferFull() = currentIndex == data.length
+
+ fun render(userdata: T) {
+ counter++
+ if (currentIndex > 0) {
+/* if (counter % 100 == 0) {
+ println("currentIndex=$currentIndex blockSize=${shaderProgram.verticesBlockSize} drawLength=${shaderProgram.drawLength} drawing=${(currentIndex / shaderProgram.verticesBlockSize).toInt()}")
+ }*/
+ if (currentIndex % shaderProgram.verticesBlockSize != 0) {
+ throw IllegalStateException("Number of vertices not a multiple of the attribute block size!")
+ }
+
+ shaderProgram.begin(attribBuffer, userdata)
+
+ webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW)
+ webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize).toInt())
+ currentIndex = 0
+
+ shaderProgram.end()
+ }
+ }
+}
diff --git a/src/com/persesgames/shooter/Shooter.kt b/src/com/persesgames/shooter/Shooter.kt
deleted file mode 100644
index 864a1b6..0000000
--- a/src/com/persesgames/shooter/Shooter.kt
+++ /dev/null
@@ -1,206 +0,0 @@
-package com.persesgames.shooter
-
-import com.persesgames.game.DrawMode
-import com.persesgames.game.Game
-import com.persesgames.game.Screen
-import com.persesgames.input.EmptyInputProcessor
-import com.persesgames.input.KeyCode
-import com.persesgames.input.Keys
-import com.persesgames.map.tiled.TiledMap
-import com.persesgames.sound.Music
-import com.persesgames.sound.Sounds
-import com.persesgames.sprite.Sprite
-import com.persesgames.sprite.SpriteBatch
-import com.persesgames.text.Texts
-import com.persesgames.texture.Textures
-import org.w3c.dom.HTMLAudioElement
-import org.w3c.dom.HTMLInputElement
-import kotlin.browser.document
-
-/**
- * Created by rnentjes on 19-4-16.
- */
-
-class GameInputProcessor : EmptyInputProcessor() {
-
- override fun keyPressed(charCode: Int) {
- println("charCode: $charCode")
- if (charCode == 32) {
- Sounds.play("EXPLOSION", 0.5f)
- } else if (charCode == 'x'.toInt()) {
- Sounds.play("DROP", 0.75f)
- }
- }
-
- override fun pointerClick(pointer: Int, x: Float, y: Float) {
- println("POINTER $pointer -> ($x, $y)")
- }
-}
-
-var music: HTMLAudioElement? = null
-var showFPS: Boolean = true
-
-class WelcomeScreen : Screen() {
-
- override fun loadResources() {
- println("loading resource!")
-
- //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
-
- Textures.loadSpriteSheet("images/data-0.json")
-
- Keys.setInputProcessor(GameInputProcessor())
- }
-
- override fun update(time: Float, delta: Float) { }
-
- override fun render() {
-
- if (showFPS) {
- Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
- }
- }
-}
-
-class GameScreen : Screen() {
- val map = TiledMap("maps", "level_1_01.json")
-
- var sprites = SpriteBatch()
- var x = 0f
- var y = 15500f
- var sprite = Sprite("SHIP")
- var numberOfSprites: Int = 5000
- var time: Float = 0f
-
- override fun loadResources() {
- Textures.load("SHIP", "images/ship2.png")
-
- Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
- Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
-
- music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
-
- Keys.setInputProcessor(GameInputProcessor())
-
- println("width: ${map.data.width}")
- println("height: ${map.data.height}")
- println("layers: ${map.data.layers?.size}")
-
- val layers = map.data.layers
- if (layers != null) {
- println("layer0: ${layers[0].name}")
- }
- val tilesets = map.data.tilesets
- if (tilesets != null) {
- println("tilesets ${tilesets.size}")
- println("tileset0: ${tilesets[0].name}")
- }
- }
-
- override fun update(time: Float, delta: Float) {
- this.time = time
- val speed = 1500f // units per second
-
- if (Keys.isDown(KeyCode.LEFT)) {
- x -= delta * speed
- println("x=$x")
- }
-
- if (Keys.isDown(KeyCode.RIGHT)) {
- x += delta * speed
- println("x=$x")
- }
-
- if (Keys.isDown(KeyCode.UP)) {
- y += delta * speed
- println("y=$y")
- }
-
- if (Keys.isDown(KeyCode.DOWN)) {
- y -= delta * speed
- println("y=$y")
- }
-
- if (Keys.isDown(KeyCode.MINUS)) {
- if (numberOfSprites > 25) {
- numberOfSprites = (numberOfSprites * 0.9f).toInt()
- }
- }
-
- if (Keys.isDown(KeyCode.PLUS)) {
- numberOfSprites = (numberOfSprites * 1.1f).toInt()
- }
- }
-
- override fun render() {
- var r = 0f
- var d = 0f
- var x = 0f
- var y = 0f
-
- map.drawLayer(1, this.x, this.y)
- map.drawLayer(2, this.x, this.y)
-
- val time = this.time / 10f
- for (index in 0..numberOfSprites) {
- r = index * 0.05f
- d = index * 2.13f
- x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
- y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
-
- sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
- }
-
- sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
-
- sprites.render()
-
- Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
-
- if (showFPS) {
- Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
- Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
- }
- }
-
-}
-
-fun main(args: Array) {
- Game.view.setToHeight(1000f)
- Game.view.drawMode = DrawMode.LINEAR
-
- Game.view.minAspectRatio = 0.9f
- Game.view.maxAspectRatio = 1.5f
-
- Game.start(WelcomeScreen())
-}
-
-fun changeMusic(it: HTMLInputElement) {
- val mus = music
-
- if (mus != null) {
- if (it.checked) {
- mus.volume = 0.5
- } else {
- mus.volume = 0.0
- }
- }
-}
-
-fun showFPS(it: HTMLInputElement) {
- showFPS = it.checked
-}
-
-fun pause(it: HTMLInputElement) {
- Game.pause = it.checked
-}
-
-fun playGame() {
- document.getElementById("menu")?.setAttribute("style", "display: none;")
-
- Game.setScreen(GameScreen())
-}
-
-fun fullscreen() {
- Game.view.requestFullscreen()
-}
diff --git a/src/com/persesgames/sound/Music.kt b/src/com/persesgames/sound/Music.kt
new file mode 100644
index 0000000..88a531d
--- /dev/null
+++ b/src/com/persesgames/sound/Music.kt
@@ -0,0 +1,49 @@
+package com.persesgames.sound
+
+import org.w3c.dom.HTMLAudioElement
+import java.util.*
+import kotlin.browser.document
+import kotlin.dom.on
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 13:02
+ */
+
+object Music {
+ val playing: MutableSet = HashSet()
+
+ fun load(url: String): HTMLAudioElement {
+ val audio = document.createElement("audio") as HTMLAudioElement
+
+ audio.src = url
+
+ return audio;
+ }
+
+ fun play(url: String, volume: Double = 0.75, looping: Boolean = false): HTMLAudioElement {
+ val audio = document.createElement("audio") as HTMLAudioElement
+
+ audio.src = url
+ audio.volume = volume
+ audio.play()
+
+ audio.on("ended", true, {
+ if (looping) {
+ audio.currentTime = 0.0
+ audio.play()
+ } else {
+ println("REMOVING: $audio")
+ audio.remove()
+ playing.remove(audio)
+ }
+ })
+
+ return audio
+ }
+
+ fun stopAll() {
+
+ }
+}
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/settings.gradle b/settings.gradle
index 329f712..3181c92 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-rootProject.name = 'kotlin-webgl-test'
+rootProject.name = 'kudens'
diff --git a/src/com/persesgames/game/Game.kt b/src/com/persesgames/game/Game.kt
new file mode 100644
index 0000000..3abdd56
--- /dev/null
+++ b/src/com/persesgames/game/Game.kt
@@ -0,0 +1,155 @@
+package com.persesgames.game
+
+import com.persesgames.texture.Textures
+import org.khronos.webgl.WebGLRenderingContext
+import org.w3c.dom.CanvasRenderingContext2D
+import org.w3c.dom.HTMLCanvasElement
+import org.w3c.dom.HTMLElement
+import kotlin.browser.document
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+enum class DrawMode {
+ LINEAR,
+ NEAREST
+}
+
+class HTMLElements {
+ var container: HTMLElement
+ var webgl: WebGLRenderingContext
+ var canvas2d: CanvasRenderingContext2D
+
+ init {
+ container = document.createElement("div") as HTMLElement
+
+ val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement
+ val canvas = document.createElement("canvas") as HTMLCanvasElement
+
+ container.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
+ webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" )
+ canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" )
+
+ document.body!!.appendChild(container)
+ container.appendChild(webGlCanvas)
+ container.appendChild(canvas)
+
+ webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext
+ canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D
+ }
+}
+
+object Game {
+ var started = false
+ val view: View = View()
+ val html: HTMLElements by lazy { HTMLElements() }
+ var currentScreen: Screen = DefaultScreen()
+ var start = Date().getTime()
+ var currentTime = start
+ var currentDelta = 0f
+ var pause: Boolean = false
+
+ var fps = 0
+ var fpsCount = 0
+ var fpsCountTime = 0f
+
+ fun gl() = html.webgl
+
+ fun resize() {
+ val canvas = gl().canvas
+
+ // Check if the canvas is not the same size.
+ val windowWidth = window.innerWidth.toInt()
+ val windowHeight = window.innerHeight.toInt()
+
+ if (view.lastWindowWidth != windowWidth ||
+ view.lastWindowHeight != windowHeight) {
+ view.lastWindowWidth = windowWidth
+ view.lastWindowHeight = windowHeight
+ view.windowWidth = windowWidth
+ view.windowHeight = windowHeight
+
+ view.updateView()
+
+ val textCanvas = html.canvas2d.canvas
+
+ // Make the canvas the same size
+ canvas.width = view.width.toInt()
+ canvas.height = view.height.toInt()
+
+ textCanvas.width = view.width.toInt()
+ textCanvas.height = view.height.toInt()
+
+ gl().viewport(0, 0, view.width.toInt(), view.height.toInt())
+
+ val left = (windowWidth - view.windowWidth) / 2
+ val top = (windowHeight - view.windowHeight) / 2
+
+ canvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ textCanvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ }
+ }
+
+ fun start(startScreen: Screen) {
+ if (started) {
+ throw IllegalStateException("You can only start a game once!")
+ }
+
+ setScreen(startScreen)
+
+ // start game loop
+ started = true
+ gameLoop()
+ }
+
+ fun setScreen(screen: Screen) {
+ currentScreen.closeResources()
+
+ currentScreen = screen
+
+ currentScreen.loadResources()
+ }
+
+ fun gameLoop() {
+ if (!Textures.ready()) {
+ Game.gl().clearColor(1f, 1f, 1f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ } else {
+ resize()
+
+ if (!pause) {
+ html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble());
+
+ Game.gl().clearColor(0f, 0f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+
+ Game.gl().enable(WebGLRenderingContext.BLEND);
+ Game.gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA); //ONE_MINUS_DST_ALPHA);
+
+ val time = Date().getTime()
+ currentDelta = (time - currentTime) / 1000f
+ currentTime = time
+
+ val timeInSeconds = (currentTime - start) / 1000f
+
+ fpsCountTime += currentDelta
+ fpsCount++
+ while (fpsCountTime > 1f) {
+ fps = fpsCount
+ fpsCountTime -= 1f
+ fpsCount = 0
+ }
+
+ currentScreen.update(timeInSeconds, currentDelta);
+ currentScreen.render()
+ }
+ }
+
+ window.requestAnimationFrame {
+ gameLoop()
+ }
+ }
+
+}
diff --git a/src/com/persesgames/game/Screen.kt b/src/com/persesgames/game/Screen.kt
new file mode 100644
index 0000000..6fb558e
--- /dev/null
+++ b/src/com/persesgames/game/Screen.kt
@@ -0,0 +1,35 @@
+package com.persesgames.game
+
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+abstract class Screen {
+
+ open fun loadResources() {
+
+ }
+
+ open fun closeResources() {
+
+ }
+
+ abstract fun update(time: Float, delta: Float)
+
+ abstract fun render()
+
+}
+
+
+class DefaultScreen: Screen() {
+ override fun update(time: Float, delta: Float) {
+ }
+
+ override fun render() {
+ // show loading message?
+ Game.gl().clearColor(1f, 1f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/game/View.kt b/src/com/persesgames/game/View.kt
new file mode 100644
index 0000000..e5590e0
--- /dev/null
+++ b/src/com/persesgames/game/View.kt
@@ -0,0 +1,221 @@
+package com.persesgames.game
+
+import com.persesgames.math.Matrix4
+
+enum class ViewType {
+ PROJECTION,
+ WIDTH,
+ HEIGHT,
+ ABSOLUTE
+}
+
+class View(
+ var lastWindowWidth: Int = 2000,
+ var lastWindowHeight: Int = 1000,
+ var windowWidth: Int = 2000,
+ var windowHeight: Int = 1000,
+ var width: Float = 1024f,
+ var height: Float = 1024f,
+ var angle: Float = 60f,
+ var near: Float = -0.1f,
+ var far: Float = -100f,
+ var minAspectRatio: Float = 1f,
+ var maxAspectRatio: Float = 1f,
+ var leftOffset: Int = 0,
+ var bottomOffset: Int = 0,
+ var viewType: ViewType = ViewType.WIDTH,
+ var drawMode: DrawMode = DrawMode.LINEAR) {
+ var vMatrix = Matrix4()
+ var aspectRatio = 1f
+
+ init {
+ updateView()
+ }
+
+ fun requestFullscreen() {
+ println("Requesting fullscreen")
+ js("""
+ if (document.webkitFullscreenElement) {
+ document.webkitCancelFullScreen();
+ } else {
+ document.documentElement.webkitRequestFullScreen();
+ }
+ """)
+ //if (document.fullscreenEnabled) {
+ // println("fullscreen Enabled")
+ //Game.html.container.requestFullscreen()
+ //document.documentElement?.requestFullscreen()
+ //}
+ }
+
+ fun updateView() {
+ aspectRatio = windowWidth / windowHeight.toFloat()
+
+ if (aspectRatio < minAspectRatio) {
+ aspectRatio = minAspectRatio
+
+ windowHeight = (windowWidth / aspectRatio).toInt()
+ }
+
+ if (aspectRatio > maxAspectRatio) {
+ aspectRatio = maxAspectRatio
+
+ windowWidth = (windowHeight * aspectRatio).toInt()
+ }
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.WIDTH -> {
+ height = width / aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.HEIGHT -> {
+ width = height * aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.PROJECTION -> {
+ vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far);
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ //println("width: $width, height: $height")
+ }
+
+ fun screenToGameCoordX(screenX: Float): Float {
+ var result = screenX
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.HEIGHT -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun screenToGameCoordY(screenY: Float): Float {
+ var result = screenY
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.HEIGHT -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordX(gameX: Float): Float {
+ var result = gameX
+ val normalizedX = gameX + (width / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.HEIGHT -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordY(gameY: Float): Float {
+ var result = gameY
+ val normalizedY = gameY + (height / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.HEIGHT -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun setToWidth(width: Float) {
+ this.width = width
+ this.viewType = ViewType.WIDTH
+
+ updateView()
+ }
+
+ fun setToHeight(height: Float) {
+ this.height = height
+ this.viewType = ViewType.HEIGHT
+
+ updateView()
+ }
+
+ fun setProjection(angle: Float) {
+ this.angle = angle
+ this.viewType = ViewType.PROJECTION
+
+ updateView()
+ }
+
+ fun setNear(near: Float) {
+ this.near = near
+
+ updateView()
+ }
+
+ fun setFar(far: Float) {
+ this.far = far
+
+ updateView()
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/input/Keys.kt b/src/com/persesgames/input/Keys.kt
new file mode 100644
index 0000000..6705c67
--- /dev/null
+++ b/src/com/persesgames/input/Keys.kt
@@ -0,0 +1,141 @@
+package com.persesgames.input
+
+import com.persesgames.game.Game
+import org.w3c.dom.events.Event
+import org.w3c.dom.events.KeyboardEvent
+import org.w3c.dom.events.MouseEvent
+import java.util.*
+import kotlin.browser.document
+import kotlin.dom.on
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 12:18
+ */
+
+enum class KeyCode(val keyCode: Int) {
+ LEFT(37),
+ UP(38),
+ DOWN(40),
+ RIGHT(39),
+ SPACE(32),
+ MINUS(109),
+ PLUS(107),
+}
+
+interface InputProcessor {
+
+ fun keyPressed(charCode: Int)
+
+ fun keyDown(keyCode: Int)
+
+ fun keyUp(keyCode: Int)
+
+ fun pointerClick(pointer: Int, x: Float, y: Float)
+
+}
+
+open class EmptyInputProcessor : InputProcessor {
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ }
+
+ override fun keyDown(keyCode: Int) {
+ }
+
+ override fun keyPressed(charCode: Int) {
+ }
+
+ override fun keyUp(keyCode: Int) {
+ }
+
+
+}
+
+object Keys {
+
+ private val keys: MutableMap = HashMap();
+ private var inputProcesser: InputProcessor = EmptyInputProcessor()
+
+ init {
+ val body = document.body
+ if (body != null) {
+ body.on("keydown", true) {
+ Keys.keyDown(it)
+ }
+
+ body.on("keyup", true) {
+ Keys.keyUp(it)
+ }
+
+ body.on("keypress", true) {
+ Keys.keyPress(it)
+ }
+
+ body.on("click", true) {
+ Keys.mouseClick(it)
+ }
+
+ body.on("mousedown", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mouseup", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mousemove", true) {
+ Keys.mouseMove(it)
+ }
+ }
+ }
+
+ fun setInputProcessor(processor: InputProcessor) {
+ this.inputProcesser = processor
+ }
+
+ private fun keyDown(key: Event) {
+ if (key is KeyboardEvent) {
+ keys.put(key.keyCode, Date().getTime())
+
+ inputProcesser.keyDown(key.keyCode)
+ }
+ }
+
+ private fun keyUp(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyUp(key.keyCode)
+
+ keys.remove(key.keyCode)
+ }
+ }
+
+ private fun keyPress(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyPressed(key.charCode)
+ }
+ }
+
+ private fun mouseClick(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+ inputProcesser.pointerClick(event.button.toInt(), vx, vy)
+ }
+ }
+
+ private fun mouseMove(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+
+ }
+ }
+
+ fun isDown(keyCode: Int) = keys.containsKey(keyCode)
+
+ fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode)
+
+}
diff --git a/src/com/persesgames/map/Map.kt b/src/com/persesgames/map/Map.kt
new file mode 100644
index 0000000..b5d7bc8
--- /dev/null
+++ b/src/com/persesgames/map/Map.kt
@@ -0,0 +1,9 @@
+package com.persesgames.map
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+open class Map {
+
+}
diff --git a/src/com/persesgames/map/tiled/TiledMap.kt b/src/com/persesgames/map/tiled/TiledMap.kt
new file mode 100644
index 0000000..a84a5a3
--- /dev/null
+++ b/src/com/persesgames/map/tiled/TiledMap.kt
@@ -0,0 +1,211 @@
+package com.persesgames.map.tiled
+
+import com.persesgames.net.getUrlAsString
+import com.persesgames.texture.Texture
+import com.persesgames.texture.Textures
+import java.util.*
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+class MapData {
+ var version: Int = 1
+ var properties: MutableMap = HashMap()
+ var layers: Array? = null
+ var tilesets: Array? = null
+
+ var height: Int = 0
+ var width: Int = 0
+
+ var nextobjectid: Int = 0
+ var orientation: String = "orthogonal"
+ var renderorder: String = "right-down"
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+}
+
+class MapLayer {
+ var properties: MutableMap = HashMap()
+
+ var data: Array? = null
+ var encoding: String = ""
+ var x: Int = 0
+ var y: Int = 0
+ var width: Int = 0
+ var height: Int = 0
+ var name: String = ""
+ var opacity: Float = 1f
+ var type: String = ""
+ var visible: Boolean = true
+ var draworder: String = ""
+}
+
+class MapTileset {
+ var properties: MutableMap = HashMap()
+
+ var firstgid: Int = 0
+ var image: String = ""
+ var imageheight: Int = 0
+ var imagewidth: Int = 0
+ var margin: Int = 0
+ var name: String = ""
+ var spacing: Int = 0
+ var tilecount: Int = 0
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+ var tileproperties: MutableMap> = HashMap()
+}
+
+class TilesetIndex(
+ val texture: Texture?,
+ val tcLeft: Float,
+ val tcTop: Float,
+ val tcRight: Float,
+ val tcBottom: Float,
+ val scale: Float
+ ) {
+ constructor() : this(null, 0f, 0f, 0f, 0f, 0f)
+
+ fun render(x: Float, y: Float) {
+ texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+}
+
+class TiledMap(dir: String = "", url: String) {
+ val properties: Map = HashMap()
+ val data: MapData
+ val tileset: Array
+ val tiles: Array
+ var first = true
+ //var tilesetIndex: Array = Array(0, { TilesetIndex() })
+
+ init {
+ var tileDir = dir
+ if (!tileDir.isEmpty() && !tileDir.endsWith("/")) {
+ tileDir = tileDir + "/"
+ }
+
+ data = JSON.parse(getUrlAsString(tileDir + url))
+ println("map data is loaded")
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ tileset = Array(tilesets.size, { "" })
+ var maxGid = 0
+ for (index in 0..tilesets.size - 1) {
+ tileset[index] = tilesets[index].name
+ Textures.load(tilesets[index].name, tileDir + tilesets[index].image)
+ maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount)
+ }
+
+ tiles = Array(maxGid, { TilesetIndex() })
+ } else {
+ tileset = Array(0, { "" })
+ tiles = Array(0, { TilesetIndex() })
+ }
+
+ cacheTiles()
+ }
+
+ fun cacheTiles() {
+ if (!Textures.ready()) {
+ window.setTimeout({ cacheTiles() }, 10)
+ } else {
+ val tilesets = data.tilesets
+ var tcLeft = 0f
+ var tcTop = 0f
+ var tcRight = 0f
+ var tcBottom = 0f
+
+ if (tilesets != null) {
+
+
+ for (tileset in tilesets) {
+ val tilesHor = tileset.imagewidth / tileset.tilewidth
+ val tilesVer = tileset.imageheight / tileset.tileheight
+ val scale = (tileset.tilewidth / tileset.imagewidth.toFloat())
+
+ for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) {
+ val texture = Textures.get(tileset.name)
+
+ val gid = index - tileset.firstgid
+
+ val xi = gid % tilesHor
+ var yi = gid / tilesHor
+ yi = tilesVer - yi - 1
+ val tw = 1f / tilesHor.toFloat()
+ val th = 1f / tilesVer.toFloat()
+
+ val pixelW = 0.1f / tileset.tilewidth
+ val pixelH = 0.1f / tileset.tileheight
+
+ tcLeft = xi * tw
+ tcRight = tcLeft + tw
+
+ // switch up/down because of texture coord 0,0 in left bottom corner
+ tcBottom = yi * th
+ tcTop = tcBottom + th
+
+ tcLeft += pixelW
+ tcRight -= pixelW
+
+ tcBottom += pixelH
+ tcTop -= pixelH
+
+ tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+ }
+ }
+ }
+ }
+
+ fun drawTile(tile: Int, x: Float, y: Float) {
+ tiles[tile].render(x, y)
+ }
+
+ fun drawLayer(layerIndex: Int, xo: Float, yo: Float) {
+ var x = 0f
+ var y = 0f
+ val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)")
+ val layer = layers[layerIndex]
+
+ val layerData = layer.data
+ if (layerData != null) {
+ for (index in layerData.indices) {
+ // todo: determine if in view
+ // todo: determine tilewidth
+ //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) {
+ drawTile(layerData[index], xo + x * 128f, yo + y * 128f)
+
+ when (data.renderorder) {
+ "right-down" -> {
+ x++
+ if (x >= layer.width) {
+ x = 0f
+ y--
+ }
+ }
+ else -> {
+ throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this")
+ }
+ }
+ //}
+ }
+ }
+
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
+
+ tx.render()
+ }
+ }
+ }
+
+
+ first = false
+ }
+}
diff --git a/src/com/persesgames/math/Matrix4.kt b/src/com/persesgames/math/Matrix4.kt
new file mode 100644
index 0000000..3cb4ed4
--- /dev/null
+++ b/src/com/persesgames/math/Matrix4.kt
@@ -0,0 +1,192 @@
+package com.persesgames.math
+
+import org.khronos.webgl.Float32Array
+
+/**
+ * User: rnentjes
+ * Date: 17-4-16
+ * Time: 15:43
+ */
+class Matrix4 {
+
+ internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ internal var temp = FloatArray(16)
+
+ private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ fun get(): FloatArray {
+ return matrix
+ }
+
+ fun getFloat32Array() = Float32Array(get().toTypedArray())
+
+ fun set(values: FloatArray) {
+ if (values.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ matrix = values
+ }
+
+ fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) {
+ val r = (angle / 180f * Math.PI).toFloat()
+ val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat()
+
+ matrix[0] = f / imageAspectRatio
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+
+ matrix[4] = 0.0f
+ matrix[5] = f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = -(far + near) / (far - near)
+ matrix[11] = -1.0f
+
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = -(2.0f * far * near) / (far - near)
+ matrix[15] = 0.0f
+ }
+
+ fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) {
+ matrix[0] = 2f / (right - left)
+ matrix[1] = 0f
+ matrix[2] = 0f
+ matrix[3] = 0f
+
+ matrix[4] = 0f
+ matrix[5] = 2f / (top - bottom)
+ matrix[6] = 0f
+ matrix[7] = 0f
+
+ matrix[8] = 0f
+ matrix[9] = 0f
+ matrix[10] = -2f / (far - near)
+ matrix[11] = 0f
+
+ matrix[12] = - (right + left) / (right - left)
+ matrix[13] = - (top + bottom) / (top - bottom)
+ matrix[14] = - (far + near) / (far - near)
+ matrix[15] = 1f
+ }
+
+ fun setToIdentity() {
+ matrix[0] = 1.0f
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+ matrix[4] = 0.0f
+ matrix[5] = 1.0f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = 1.0f
+ matrix[11] = 0.0f
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = 0.0f
+ matrix[15] = 1.0f
+ }
+
+ fun mul(other: Matrix4) {
+ mul(other.get())
+ }
+
+ protected fun mul(other: FloatArray) {
+ if (other.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12]
+ temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13]
+ temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14]
+ temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15]
+ temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12]
+ temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13]
+ temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14]
+ temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15]
+ temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12]
+ temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13]
+ temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14]
+ temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15]
+ temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12]
+ temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13]
+ temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14]
+ temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15]
+
+ matrix[0] = temp[0]
+ matrix[1] = temp[1]
+ matrix[2] = temp[2]
+ matrix[3] = temp[3]
+ matrix[4] = temp[4]
+ matrix[5] = temp[5]
+ matrix[6] = temp[6]
+ matrix[7] = temp[7]
+ matrix[8] = temp[8]
+ matrix[9] = temp[9]
+ matrix[10] = temp[10]
+ matrix[11] = temp[11]
+ matrix[12] = temp[12]
+ matrix[13] = temp[13]
+ matrix[14] = temp[14]
+ matrix[15] = temp[15]
+ }
+
+ fun translate(x: Float, y: Float, z: Float) {
+ translateMatrix[12] = x
+ translateMatrix[13] = y
+ translateMatrix[14] = z
+
+ mul(translateMatrix)
+ }
+
+ fun scale(x: Float, y: Float, z: Float) {
+ scaleMatrix[0] = x
+ scaleMatrix[5] = y
+ scaleMatrix[10] = z
+
+ mul(scaleMatrix)
+ }
+
+ fun rotateX(angle: Float) {
+ rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+ rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat()
+ rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateXMatrix)
+ }
+
+ fun rotateY(angle: Float) {
+ rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat()
+ rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateYMatrix)
+ }
+
+ fun rotateZ(angle: Float) {
+ rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat()
+ rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateZMatrix)
+ }
+}
diff --git a/src/com/persesgames/net/NetUtils.kt b/src/com/persesgames/net/NetUtils.kt
new file mode 100644
index 0000000..b59cbb3
--- /dev/null
+++ b/src/com/persesgames/net/NetUtils.kt
@@ -0,0 +1,18 @@
+package com.persesgames.net
+
+import org.w3c.xhr.XMLHttpRequest
+
+/**
+ * User: rnentjes
+ * Date: 30-7-16
+ * Time: 16:39
+ */
+
+fun getUrlAsString(url: String): String {
+ val req = XMLHttpRequest()
+
+ req.open("GET", url, false)
+ req.send(null)
+
+ return req.responseText
+}
diff --git a/src/com/persesgames/shader/ShaderProgram.kt b/src/com/persesgames/shader/ShaderProgram.kt
new file mode 100644
index 0000000..3c3aad5
--- /dev/null
+++ b/src/com/persesgames/shader/ShaderProgram.kt
@@ -0,0 +1,110 @@
+package com.persesgames.shader
+
+import org.khronos.webgl.*
+
+/**
+ * User: rnentjes
+ * Date: 17-4-16
+ * Time: 15:15
+ */
+
+class ShaderProgram(
+ val webgl: WebGLRenderingContext,
+ val drawType: Int,
+ vertexShaderSource: String,
+ fragmentShaderSource: String,
+ val vainfo: Array,
+ val setter: (program: ShaderProgram, data: T) -> Unit) {
+
+ var shaderProgram: WebGLProgram
+ var vertex: WebGLShader
+ var fragment: WebGLShader
+
+ var verticesBlockSize = 0
+ var drawLength = 0
+
+ init {
+ vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER)
+ fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER)
+
+ shaderProgram = webgl.createProgram() ?: throw IllegalStateException("Unable to request shader program from webgl context!")
+ webgl.attachShader(shaderProgram, vertex)
+ webgl.attachShader(shaderProgram, fragment)
+ webgl.linkProgram(shaderProgram)
+
+ if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) {
+ println(webgl.getProgramInfoLog(shaderProgram))
+ throw IllegalStateException("Unable to compile shader program!")
+ }
+
+ webgl.useProgram(shaderProgram)
+
+ this.verticesBlockSize = 0;
+
+ // set attribute locations...
+ for (info in vainfo.iterator()) {
+ info.location = webgl.getAttribLocation(shaderProgram, info.locationName)
+ info.offset = verticesBlockSize;
+
+ verticesBlockSize += info.numElements;
+ println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}");
+ }
+
+ when(drawType) {
+ WebGLRenderingContext.TRIANGLES -> {
+ drawLength = verticesBlockSize * 3
+ }
+ else -> {
+ drawLength = verticesBlockSize
+ }
+ }
+
+ println("verticesBlockSize $verticesBlockSize");
+
+ println("ShaderProgram constructor done");
+ }
+
+ private fun compileShader(source: String, type: Int): WebGLShader {
+ val result: WebGLShader
+
+ result = webgl.createShader(type) ?: throw IllegalStateException("Unable to request shader from webgl context!")
+ webgl.shaderSource(result, source)
+ webgl.compileShader(result)
+
+ if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) {
+ throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}")
+ }
+
+ return result
+ }
+
+ fun begin(attribBuffer: WebGLBuffer, userdata: T) {
+ webgl.useProgram(shaderProgram);
+ webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer);
+
+ // set attribute locations...
+ for (info in vainfo.iterator()) {
+ webgl.enableVertexAttribArray(info.location)
+ webgl.vertexAttribPointer(info.location, info.numElements, WebGLRenderingContext.FLOAT, false, verticesBlockSize * 4, info.offset * 4)
+ }
+
+ setter(this, userdata)
+ }
+
+ fun end() {
+ for (info in vainfo.iterator()) {
+ webgl.disableVertexAttribArray(info.location);
+ }
+ webgl.useProgram(null)
+ }
+
+ fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location);
+
+ fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location);
+
+ fun setUniform1f(location: String, value: Float) { webgl.uniform1f(getUniformLocation(location), value); }
+ fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); }
+ fun setUniform1i(location: String, value: Int) { webgl.uniform1i(getUniformLocation(location), value); }
+ fun setUniformMatrix4fv(location: String, value: Float32Array) { webgl.uniformMatrix4fv(getUniformLocation(location), false, value); }
+
+}
diff --git a/src/com/persesgames/shader/ShaderProgramMesh.kt b/src/com/persesgames/shader/ShaderProgramMesh.kt
new file mode 100644
index 0000000..f4c4dd5
--- /dev/null
+++ b/src/com/persesgames/shader/ShaderProgramMesh.kt
@@ -0,0 +1,71 @@
+package com.persesgames.shader
+
+import org.khronos.webgl.Float32Array
+import org.khronos.webgl.WebGLBuffer
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * User: rnentjes
+ * Date: 14-5-16
+ * Time: 11:57
+ */
+
+class VertextAttributeInfo(val locationName: String, val numElements: Int) {
+ var location = 0
+ var offset = 0
+}
+
+class ShaderProgramMesh(
+ val shaderProgram: ShaderProgram
+) {
+ val webgl = shaderProgram.webgl
+ val data: Float32Array
+ var currentIndex: Int = 0
+ val attribBuffer: WebGLBuffer
+ var counter = 0
+
+ init {
+ data = Float32Array(20000 - (20000 % shaderProgram.drawLength))
+
+ attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!")
+ webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer);
+ }
+
+ fun queue(vararg vertices: Float) {
+ queue(vertices as Array)
+ }
+
+ fun queue(vertices: Array) {
+ data.set(vertices, currentIndex)
+ currentIndex += vertices.size
+
+ if (currentIndex == data.length) {
+ println("Skipped draw call, to many values!")
+ currentIndex = 0
+ }
+ }
+
+ fun remaining() = data.length - currentIndex
+
+ fun bufferFull() = currentIndex == data.length
+
+ fun render(userdata: T) {
+ counter++
+ if (currentIndex > 0) {
+/* if (counter % 100 == 0) {
+ println("currentIndex=$currentIndex blockSize=${shaderProgram.verticesBlockSize} drawLength=${shaderProgram.drawLength} drawing=${(currentIndex / shaderProgram.verticesBlockSize).toInt()}")
+ }*/
+ if (currentIndex % shaderProgram.verticesBlockSize != 0) {
+ throw IllegalStateException("Number of vertices not a multiple of the attribute block size!")
+ }
+
+ shaderProgram.begin(attribBuffer, userdata)
+
+ webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW)
+ webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize).toInt())
+ currentIndex = 0
+
+ shaderProgram.end()
+ }
+ }
+}
diff --git a/src/com/persesgames/shooter/Shooter.kt b/src/com/persesgames/shooter/Shooter.kt
deleted file mode 100644
index 864a1b6..0000000
--- a/src/com/persesgames/shooter/Shooter.kt
+++ /dev/null
@@ -1,206 +0,0 @@
-package com.persesgames.shooter
-
-import com.persesgames.game.DrawMode
-import com.persesgames.game.Game
-import com.persesgames.game.Screen
-import com.persesgames.input.EmptyInputProcessor
-import com.persesgames.input.KeyCode
-import com.persesgames.input.Keys
-import com.persesgames.map.tiled.TiledMap
-import com.persesgames.sound.Music
-import com.persesgames.sound.Sounds
-import com.persesgames.sprite.Sprite
-import com.persesgames.sprite.SpriteBatch
-import com.persesgames.text.Texts
-import com.persesgames.texture.Textures
-import org.w3c.dom.HTMLAudioElement
-import org.w3c.dom.HTMLInputElement
-import kotlin.browser.document
-
-/**
- * Created by rnentjes on 19-4-16.
- */
-
-class GameInputProcessor : EmptyInputProcessor() {
-
- override fun keyPressed(charCode: Int) {
- println("charCode: $charCode")
- if (charCode == 32) {
- Sounds.play("EXPLOSION", 0.5f)
- } else if (charCode == 'x'.toInt()) {
- Sounds.play("DROP", 0.75f)
- }
- }
-
- override fun pointerClick(pointer: Int, x: Float, y: Float) {
- println("POINTER $pointer -> ($x, $y)")
- }
-}
-
-var music: HTMLAudioElement? = null
-var showFPS: Boolean = true
-
-class WelcomeScreen : Screen() {
-
- override fun loadResources() {
- println("loading resource!")
-
- //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
-
- Textures.loadSpriteSheet("images/data-0.json")
-
- Keys.setInputProcessor(GameInputProcessor())
- }
-
- override fun update(time: Float, delta: Float) { }
-
- override fun render() {
-
- if (showFPS) {
- Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
- }
- }
-}
-
-class GameScreen : Screen() {
- val map = TiledMap("maps", "level_1_01.json")
-
- var sprites = SpriteBatch()
- var x = 0f
- var y = 15500f
- var sprite = Sprite("SHIP")
- var numberOfSprites: Int = 5000
- var time: Float = 0f
-
- override fun loadResources() {
- Textures.load("SHIP", "images/ship2.png")
-
- Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
- Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
-
- music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
-
- Keys.setInputProcessor(GameInputProcessor())
-
- println("width: ${map.data.width}")
- println("height: ${map.data.height}")
- println("layers: ${map.data.layers?.size}")
-
- val layers = map.data.layers
- if (layers != null) {
- println("layer0: ${layers[0].name}")
- }
- val tilesets = map.data.tilesets
- if (tilesets != null) {
- println("tilesets ${tilesets.size}")
- println("tileset0: ${tilesets[0].name}")
- }
- }
-
- override fun update(time: Float, delta: Float) {
- this.time = time
- val speed = 1500f // units per second
-
- if (Keys.isDown(KeyCode.LEFT)) {
- x -= delta * speed
- println("x=$x")
- }
-
- if (Keys.isDown(KeyCode.RIGHT)) {
- x += delta * speed
- println("x=$x")
- }
-
- if (Keys.isDown(KeyCode.UP)) {
- y += delta * speed
- println("y=$y")
- }
-
- if (Keys.isDown(KeyCode.DOWN)) {
- y -= delta * speed
- println("y=$y")
- }
-
- if (Keys.isDown(KeyCode.MINUS)) {
- if (numberOfSprites > 25) {
- numberOfSprites = (numberOfSprites * 0.9f).toInt()
- }
- }
-
- if (Keys.isDown(KeyCode.PLUS)) {
- numberOfSprites = (numberOfSprites * 1.1f).toInt()
- }
- }
-
- override fun render() {
- var r = 0f
- var d = 0f
- var x = 0f
- var y = 0f
-
- map.drawLayer(1, this.x, this.y)
- map.drawLayer(2, this.x, this.y)
-
- val time = this.time / 10f
- for (index in 0..numberOfSprites) {
- r = index * 0.05f
- d = index * 2.13f
- x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
- y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
-
- sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
- }
-
- sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
-
- sprites.render()
-
- Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
-
- if (showFPS) {
- Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
- Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
- }
- }
-
-}
-
-fun main(args: Array) {
- Game.view.setToHeight(1000f)
- Game.view.drawMode = DrawMode.LINEAR
-
- Game.view.minAspectRatio = 0.9f
- Game.view.maxAspectRatio = 1.5f
-
- Game.start(WelcomeScreen())
-}
-
-fun changeMusic(it: HTMLInputElement) {
- val mus = music
-
- if (mus != null) {
- if (it.checked) {
- mus.volume = 0.5
- } else {
- mus.volume = 0.0
- }
- }
-}
-
-fun showFPS(it: HTMLInputElement) {
- showFPS = it.checked
-}
-
-fun pause(it: HTMLInputElement) {
- Game.pause = it.checked
-}
-
-fun playGame() {
- document.getElementById("menu")?.setAttribute("style", "display: none;")
-
- Game.setScreen(GameScreen())
-}
-
-fun fullscreen() {
- Game.view.requestFullscreen()
-}
diff --git a/src/com/persesgames/sound/Music.kt b/src/com/persesgames/sound/Music.kt
new file mode 100644
index 0000000..88a531d
--- /dev/null
+++ b/src/com/persesgames/sound/Music.kt
@@ -0,0 +1,49 @@
+package com.persesgames.sound
+
+import org.w3c.dom.HTMLAudioElement
+import java.util.*
+import kotlin.browser.document
+import kotlin.dom.on
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 13:02
+ */
+
+object Music {
+ val playing: MutableSet = HashSet()
+
+ fun load(url: String): HTMLAudioElement {
+ val audio = document.createElement("audio") as HTMLAudioElement
+
+ audio.src = url
+
+ return audio;
+ }
+
+ fun play(url: String, volume: Double = 0.75, looping: Boolean = false): HTMLAudioElement {
+ val audio = document.createElement("audio") as HTMLAudioElement
+
+ audio.src = url
+ audio.volume = volume
+ audio.play()
+
+ audio.on("ended", true, {
+ if (looping) {
+ audio.currentTime = 0.0
+ audio.play()
+ } else {
+ println("REMOVING: $audio")
+ audio.remove()
+ playing.remove(audio)
+ }
+ })
+
+ return audio
+ }
+
+ fun stopAll() {
+
+ }
+}
diff --git a/src/com/persesgames/sound/Sounds.kt b/src/com/persesgames/sound/Sounds.kt
new file mode 100644
index 0000000..8d8c549
--- /dev/null
+++ b/src/com/persesgames/sound/Sounds.kt
@@ -0,0 +1,62 @@
+package com.persesgames.sound
+
+import org.w3c.dom.HTMLAudioElement
+import java.util.*
+import kotlin.browser.document
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 12:34
+ */
+
+class Sound(val name:String, val url: String, val volume: Double = 0.75, val numberOfChannels: Int) {
+ var channels: Array
+ var nextChannel: Int = 0
+
+ init {
+ println("CREATING: $name")
+ channels = Array(numberOfChannels, { document.createElement("audio") as HTMLAudioElement })
+
+ for (audio in channels) {
+ audio.src = url
+ audio.pause()
+ audio.load()
+ audio.volume = volume
+ }
+ }
+
+ fun play() {
+ println("PLAYING: $name - $nextChannel")
+ channels[nextChannel].currentTime = 0.0
+ channels[nextChannel].play()
+
+ nextChannel = (nextChannel + 1) % channels.size
+ }
+
+ fun pause() {
+ for (audio in channels) {
+ audio.pause()
+ }
+ }
+}
+
+object Sounds {
+ val sounds: MutableMap = HashMap()
+
+ fun load(name: String, url: String, volume: Double = 0.75, channels: Int = 1 ) {
+ sounds.put(name, Sound(name, url, volume, channels))
+ }
+
+ fun play(name: String, volume: Float = 0.75f) {
+ val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!")
+
+ sound.play()
+ }
+
+ fun pause(name: String) {
+ val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!")
+
+ sound.pause()
+ }
+}
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/settings.gradle b/settings.gradle
index 329f712..3181c92 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-rootProject.name = 'kotlin-webgl-test'
+rootProject.name = 'kudens'
diff --git a/src/com/persesgames/game/Game.kt b/src/com/persesgames/game/Game.kt
new file mode 100644
index 0000000..3abdd56
--- /dev/null
+++ b/src/com/persesgames/game/Game.kt
@@ -0,0 +1,155 @@
+package com.persesgames.game
+
+import com.persesgames.texture.Textures
+import org.khronos.webgl.WebGLRenderingContext
+import org.w3c.dom.CanvasRenderingContext2D
+import org.w3c.dom.HTMLCanvasElement
+import org.w3c.dom.HTMLElement
+import kotlin.browser.document
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+enum class DrawMode {
+ LINEAR,
+ NEAREST
+}
+
+class HTMLElements {
+ var container: HTMLElement
+ var webgl: WebGLRenderingContext
+ var canvas2d: CanvasRenderingContext2D
+
+ init {
+ container = document.createElement("div") as HTMLElement
+
+ val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement
+ val canvas = document.createElement("canvas") as HTMLCanvasElement
+
+ container.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
+ webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" )
+ canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" )
+
+ document.body!!.appendChild(container)
+ container.appendChild(webGlCanvas)
+ container.appendChild(canvas)
+
+ webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext
+ canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D
+ }
+}
+
+object Game {
+ var started = false
+ val view: View = View()
+ val html: HTMLElements by lazy { HTMLElements() }
+ var currentScreen: Screen = DefaultScreen()
+ var start = Date().getTime()
+ var currentTime = start
+ var currentDelta = 0f
+ var pause: Boolean = false
+
+ var fps = 0
+ var fpsCount = 0
+ var fpsCountTime = 0f
+
+ fun gl() = html.webgl
+
+ fun resize() {
+ val canvas = gl().canvas
+
+ // Check if the canvas is not the same size.
+ val windowWidth = window.innerWidth.toInt()
+ val windowHeight = window.innerHeight.toInt()
+
+ if (view.lastWindowWidth != windowWidth ||
+ view.lastWindowHeight != windowHeight) {
+ view.lastWindowWidth = windowWidth
+ view.lastWindowHeight = windowHeight
+ view.windowWidth = windowWidth
+ view.windowHeight = windowHeight
+
+ view.updateView()
+
+ val textCanvas = html.canvas2d.canvas
+
+ // Make the canvas the same size
+ canvas.width = view.width.toInt()
+ canvas.height = view.height.toInt()
+
+ textCanvas.width = view.width.toInt()
+ textCanvas.height = view.height.toInt()
+
+ gl().viewport(0, 0, view.width.toInt(), view.height.toInt())
+
+ val left = (windowWidth - view.windowWidth) / 2
+ val top = (windowHeight - view.windowHeight) / 2
+
+ canvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ textCanvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ }
+ }
+
+ fun start(startScreen: Screen) {
+ if (started) {
+ throw IllegalStateException("You can only start a game once!")
+ }
+
+ setScreen(startScreen)
+
+ // start game loop
+ started = true
+ gameLoop()
+ }
+
+ fun setScreen(screen: Screen) {
+ currentScreen.closeResources()
+
+ currentScreen = screen
+
+ currentScreen.loadResources()
+ }
+
+ fun gameLoop() {
+ if (!Textures.ready()) {
+ Game.gl().clearColor(1f, 1f, 1f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ } else {
+ resize()
+
+ if (!pause) {
+ html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble());
+
+ Game.gl().clearColor(0f, 0f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+
+ Game.gl().enable(WebGLRenderingContext.BLEND);
+ Game.gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA); //ONE_MINUS_DST_ALPHA);
+
+ val time = Date().getTime()
+ currentDelta = (time - currentTime) / 1000f
+ currentTime = time
+
+ val timeInSeconds = (currentTime - start) / 1000f
+
+ fpsCountTime += currentDelta
+ fpsCount++
+ while (fpsCountTime > 1f) {
+ fps = fpsCount
+ fpsCountTime -= 1f
+ fpsCount = 0
+ }
+
+ currentScreen.update(timeInSeconds, currentDelta);
+ currentScreen.render()
+ }
+ }
+
+ window.requestAnimationFrame {
+ gameLoop()
+ }
+ }
+
+}
diff --git a/src/com/persesgames/game/Screen.kt b/src/com/persesgames/game/Screen.kt
new file mode 100644
index 0000000..6fb558e
--- /dev/null
+++ b/src/com/persesgames/game/Screen.kt
@@ -0,0 +1,35 @@
+package com.persesgames.game
+
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+abstract class Screen {
+
+ open fun loadResources() {
+
+ }
+
+ open fun closeResources() {
+
+ }
+
+ abstract fun update(time: Float, delta: Float)
+
+ abstract fun render()
+
+}
+
+
+class DefaultScreen: Screen() {
+ override fun update(time: Float, delta: Float) {
+ }
+
+ override fun render() {
+ // show loading message?
+ Game.gl().clearColor(1f, 1f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/game/View.kt b/src/com/persesgames/game/View.kt
new file mode 100644
index 0000000..e5590e0
--- /dev/null
+++ b/src/com/persesgames/game/View.kt
@@ -0,0 +1,221 @@
+package com.persesgames.game
+
+import com.persesgames.math.Matrix4
+
+enum class ViewType {
+ PROJECTION,
+ WIDTH,
+ HEIGHT,
+ ABSOLUTE
+}
+
+class View(
+ var lastWindowWidth: Int = 2000,
+ var lastWindowHeight: Int = 1000,
+ var windowWidth: Int = 2000,
+ var windowHeight: Int = 1000,
+ var width: Float = 1024f,
+ var height: Float = 1024f,
+ var angle: Float = 60f,
+ var near: Float = -0.1f,
+ var far: Float = -100f,
+ var minAspectRatio: Float = 1f,
+ var maxAspectRatio: Float = 1f,
+ var leftOffset: Int = 0,
+ var bottomOffset: Int = 0,
+ var viewType: ViewType = ViewType.WIDTH,
+ var drawMode: DrawMode = DrawMode.LINEAR) {
+ var vMatrix = Matrix4()
+ var aspectRatio = 1f
+
+ init {
+ updateView()
+ }
+
+ fun requestFullscreen() {
+ println("Requesting fullscreen")
+ js("""
+ if (document.webkitFullscreenElement) {
+ document.webkitCancelFullScreen();
+ } else {
+ document.documentElement.webkitRequestFullScreen();
+ }
+ """)
+ //if (document.fullscreenEnabled) {
+ // println("fullscreen Enabled")
+ //Game.html.container.requestFullscreen()
+ //document.documentElement?.requestFullscreen()
+ //}
+ }
+
+ fun updateView() {
+ aspectRatio = windowWidth / windowHeight.toFloat()
+
+ if (aspectRatio < minAspectRatio) {
+ aspectRatio = minAspectRatio
+
+ windowHeight = (windowWidth / aspectRatio).toInt()
+ }
+
+ if (aspectRatio > maxAspectRatio) {
+ aspectRatio = maxAspectRatio
+
+ windowWidth = (windowHeight * aspectRatio).toInt()
+ }
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.WIDTH -> {
+ height = width / aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.HEIGHT -> {
+ width = height * aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.PROJECTION -> {
+ vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far);
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ //println("width: $width, height: $height")
+ }
+
+ fun screenToGameCoordX(screenX: Float): Float {
+ var result = screenX
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.HEIGHT -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun screenToGameCoordY(screenY: Float): Float {
+ var result = screenY
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.HEIGHT -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordX(gameX: Float): Float {
+ var result = gameX
+ val normalizedX = gameX + (width / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.HEIGHT -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordY(gameY: Float): Float {
+ var result = gameY
+ val normalizedY = gameY + (height / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.HEIGHT -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun setToWidth(width: Float) {
+ this.width = width
+ this.viewType = ViewType.WIDTH
+
+ updateView()
+ }
+
+ fun setToHeight(height: Float) {
+ this.height = height
+ this.viewType = ViewType.HEIGHT
+
+ updateView()
+ }
+
+ fun setProjection(angle: Float) {
+ this.angle = angle
+ this.viewType = ViewType.PROJECTION
+
+ updateView()
+ }
+
+ fun setNear(near: Float) {
+ this.near = near
+
+ updateView()
+ }
+
+ fun setFar(far: Float) {
+ this.far = far
+
+ updateView()
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/input/Keys.kt b/src/com/persesgames/input/Keys.kt
new file mode 100644
index 0000000..6705c67
--- /dev/null
+++ b/src/com/persesgames/input/Keys.kt
@@ -0,0 +1,141 @@
+package com.persesgames.input
+
+import com.persesgames.game.Game
+import org.w3c.dom.events.Event
+import org.w3c.dom.events.KeyboardEvent
+import org.w3c.dom.events.MouseEvent
+import java.util.*
+import kotlin.browser.document
+import kotlin.dom.on
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 12:18
+ */
+
+enum class KeyCode(val keyCode: Int) {
+ LEFT(37),
+ UP(38),
+ DOWN(40),
+ RIGHT(39),
+ SPACE(32),
+ MINUS(109),
+ PLUS(107),
+}
+
+interface InputProcessor {
+
+ fun keyPressed(charCode: Int)
+
+ fun keyDown(keyCode: Int)
+
+ fun keyUp(keyCode: Int)
+
+ fun pointerClick(pointer: Int, x: Float, y: Float)
+
+}
+
+open class EmptyInputProcessor : InputProcessor {
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ }
+
+ override fun keyDown(keyCode: Int) {
+ }
+
+ override fun keyPressed(charCode: Int) {
+ }
+
+ override fun keyUp(keyCode: Int) {
+ }
+
+
+}
+
+object Keys {
+
+ private val keys: MutableMap = HashMap();
+ private var inputProcesser: InputProcessor = EmptyInputProcessor()
+
+ init {
+ val body = document.body
+ if (body != null) {
+ body.on("keydown", true) {
+ Keys.keyDown(it)
+ }
+
+ body.on("keyup", true) {
+ Keys.keyUp(it)
+ }
+
+ body.on("keypress", true) {
+ Keys.keyPress(it)
+ }
+
+ body.on("click", true) {
+ Keys.mouseClick(it)
+ }
+
+ body.on("mousedown", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mouseup", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mousemove", true) {
+ Keys.mouseMove(it)
+ }
+ }
+ }
+
+ fun setInputProcessor(processor: InputProcessor) {
+ this.inputProcesser = processor
+ }
+
+ private fun keyDown(key: Event) {
+ if (key is KeyboardEvent) {
+ keys.put(key.keyCode, Date().getTime())
+
+ inputProcesser.keyDown(key.keyCode)
+ }
+ }
+
+ private fun keyUp(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyUp(key.keyCode)
+
+ keys.remove(key.keyCode)
+ }
+ }
+
+ private fun keyPress(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyPressed(key.charCode)
+ }
+ }
+
+ private fun mouseClick(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+ inputProcesser.pointerClick(event.button.toInt(), vx, vy)
+ }
+ }
+
+ private fun mouseMove(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+
+ }
+ }
+
+ fun isDown(keyCode: Int) = keys.containsKey(keyCode)
+
+ fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode)
+
+}
diff --git a/src/com/persesgames/map/Map.kt b/src/com/persesgames/map/Map.kt
new file mode 100644
index 0000000..b5d7bc8
--- /dev/null
+++ b/src/com/persesgames/map/Map.kt
@@ -0,0 +1,9 @@
+package com.persesgames.map
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+open class Map {
+
+}
diff --git a/src/com/persesgames/map/tiled/TiledMap.kt b/src/com/persesgames/map/tiled/TiledMap.kt
new file mode 100644
index 0000000..a84a5a3
--- /dev/null
+++ b/src/com/persesgames/map/tiled/TiledMap.kt
@@ -0,0 +1,211 @@
+package com.persesgames.map.tiled
+
+import com.persesgames.net.getUrlAsString
+import com.persesgames.texture.Texture
+import com.persesgames.texture.Textures
+import java.util.*
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+class MapData {
+ var version: Int = 1
+ var properties: MutableMap = HashMap()
+ var layers: Array? = null
+ var tilesets: Array? = null
+
+ var height: Int = 0
+ var width: Int = 0
+
+ var nextobjectid: Int = 0
+ var orientation: String = "orthogonal"
+ var renderorder: String = "right-down"
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+}
+
+class MapLayer {
+ var properties: MutableMap = HashMap()
+
+ var data: Array? = null
+ var encoding: String = ""
+ var x: Int = 0
+ var y: Int = 0
+ var width: Int = 0
+ var height: Int = 0
+ var name: String = ""
+ var opacity: Float = 1f
+ var type: String = ""
+ var visible: Boolean = true
+ var draworder: String = ""
+}
+
+class MapTileset {
+ var properties: MutableMap = HashMap()
+
+ var firstgid: Int = 0
+ var image: String = ""
+ var imageheight: Int = 0
+ var imagewidth: Int = 0
+ var margin: Int = 0
+ var name: String = ""
+ var spacing: Int = 0
+ var tilecount: Int = 0
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+ var tileproperties: MutableMap> = HashMap()
+}
+
+class TilesetIndex(
+ val texture: Texture?,
+ val tcLeft: Float,
+ val tcTop: Float,
+ val tcRight: Float,
+ val tcBottom: Float,
+ val scale: Float
+ ) {
+ constructor() : this(null, 0f, 0f, 0f, 0f, 0f)
+
+ fun render(x: Float, y: Float) {
+ texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+}
+
+class TiledMap(dir: String = "", url: String) {
+ val properties: Map = HashMap()
+ val data: MapData
+ val tileset: Array
+ val tiles: Array
+ var first = true
+ //var tilesetIndex: Array = Array(0, { TilesetIndex() })
+
+ init {
+ var tileDir = dir
+ if (!tileDir.isEmpty() && !tileDir.endsWith("/")) {
+ tileDir = tileDir + "/"
+ }
+
+ data = JSON.parse(getUrlAsString(tileDir + url))
+ println("map data is loaded")
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ tileset = Array(tilesets.size, { "" })
+ var maxGid = 0
+ for (index in 0..tilesets.size - 1) {
+ tileset[index] = tilesets[index].name
+ Textures.load(tilesets[index].name, tileDir + tilesets[index].image)
+ maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount)
+ }
+
+ tiles = Array(maxGid, { TilesetIndex() })
+ } else {
+ tileset = Array(0, { "" })
+ tiles = Array(0, { TilesetIndex() })
+ }
+
+ cacheTiles()
+ }
+
+ fun cacheTiles() {
+ if (!Textures.ready()) {
+ window.setTimeout({ cacheTiles() }, 10)
+ } else {
+ val tilesets = data.tilesets
+ var tcLeft = 0f
+ var tcTop = 0f
+ var tcRight = 0f
+ var tcBottom = 0f
+
+ if (tilesets != null) {
+
+
+ for (tileset in tilesets) {
+ val tilesHor = tileset.imagewidth / tileset.tilewidth
+ val tilesVer = tileset.imageheight / tileset.tileheight
+ val scale = (tileset.tilewidth / tileset.imagewidth.toFloat())
+
+ for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) {
+ val texture = Textures.get(tileset.name)
+
+ val gid = index - tileset.firstgid
+
+ val xi = gid % tilesHor
+ var yi = gid / tilesHor
+ yi = tilesVer - yi - 1
+ val tw = 1f / tilesHor.toFloat()
+ val th = 1f / tilesVer.toFloat()
+
+ val pixelW = 0.1f / tileset.tilewidth
+ val pixelH = 0.1f / tileset.tileheight
+
+ tcLeft = xi * tw
+ tcRight = tcLeft + tw
+
+ // switch up/down because of texture coord 0,0 in left bottom corner
+ tcBottom = yi * th
+ tcTop = tcBottom + th
+
+ tcLeft += pixelW
+ tcRight -= pixelW
+
+ tcBottom += pixelH
+ tcTop -= pixelH
+
+ tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+ }
+ }
+ }
+ }
+
+ fun drawTile(tile: Int, x: Float, y: Float) {
+ tiles[tile].render(x, y)
+ }
+
+ fun drawLayer(layerIndex: Int, xo: Float, yo: Float) {
+ var x = 0f
+ var y = 0f
+ val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)")
+ val layer = layers[layerIndex]
+
+ val layerData = layer.data
+ if (layerData != null) {
+ for (index in layerData.indices) {
+ // todo: determine if in view
+ // todo: determine tilewidth
+ //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) {
+ drawTile(layerData[index], xo + x * 128f, yo + y * 128f)
+
+ when (data.renderorder) {
+ "right-down" -> {
+ x++
+ if (x >= layer.width) {
+ x = 0f
+ y--
+ }
+ }
+ else -> {
+ throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this")
+ }
+ }
+ //}
+ }
+ }
+
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
+
+ tx.render()
+ }
+ }
+ }
+
+
+ first = false
+ }
+}
diff --git a/src/com/persesgames/math/Matrix4.kt b/src/com/persesgames/math/Matrix4.kt
new file mode 100644
index 0000000..3cb4ed4
--- /dev/null
+++ b/src/com/persesgames/math/Matrix4.kt
@@ -0,0 +1,192 @@
+package com.persesgames.math
+
+import org.khronos.webgl.Float32Array
+
+/**
+ * User: rnentjes
+ * Date: 17-4-16
+ * Time: 15:43
+ */
+class Matrix4 {
+
+ internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ internal var temp = FloatArray(16)
+
+ private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ fun get(): FloatArray {
+ return matrix
+ }
+
+ fun getFloat32Array() = Float32Array(get().toTypedArray())
+
+ fun set(values: FloatArray) {
+ if (values.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ matrix = values
+ }
+
+ fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) {
+ val r = (angle / 180f * Math.PI).toFloat()
+ val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat()
+
+ matrix[0] = f / imageAspectRatio
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+
+ matrix[4] = 0.0f
+ matrix[5] = f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = -(far + near) / (far - near)
+ matrix[11] = -1.0f
+
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = -(2.0f * far * near) / (far - near)
+ matrix[15] = 0.0f
+ }
+
+ fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) {
+ matrix[0] = 2f / (right - left)
+ matrix[1] = 0f
+ matrix[2] = 0f
+ matrix[3] = 0f
+
+ matrix[4] = 0f
+ matrix[5] = 2f / (top - bottom)
+ matrix[6] = 0f
+ matrix[7] = 0f
+
+ matrix[8] = 0f
+ matrix[9] = 0f
+ matrix[10] = -2f / (far - near)
+ matrix[11] = 0f
+
+ matrix[12] = - (right + left) / (right - left)
+ matrix[13] = - (top + bottom) / (top - bottom)
+ matrix[14] = - (far + near) / (far - near)
+ matrix[15] = 1f
+ }
+
+ fun setToIdentity() {
+ matrix[0] = 1.0f
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+ matrix[4] = 0.0f
+ matrix[5] = 1.0f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = 1.0f
+ matrix[11] = 0.0f
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = 0.0f
+ matrix[15] = 1.0f
+ }
+
+ fun mul(other: Matrix4) {
+ mul(other.get())
+ }
+
+ protected fun mul(other: FloatArray) {
+ if (other.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12]
+ temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13]
+ temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14]
+ temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15]
+ temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12]
+ temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13]
+ temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14]
+ temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15]
+ temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12]
+ temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13]
+ temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14]
+ temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15]
+ temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12]
+ temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13]
+ temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14]
+ temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15]
+
+ matrix[0] = temp[0]
+ matrix[1] = temp[1]
+ matrix[2] = temp[2]
+ matrix[3] = temp[3]
+ matrix[4] = temp[4]
+ matrix[5] = temp[5]
+ matrix[6] = temp[6]
+ matrix[7] = temp[7]
+ matrix[8] = temp[8]
+ matrix[9] = temp[9]
+ matrix[10] = temp[10]
+ matrix[11] = temp[11]
+ matrix[12] = temp[12]
+ matrix[13] = temp[13]
+ matrix[14] = temp[14]
+ matrix[15] = temp[15]
+ }
+
+ fun translate(x: Float, y: Float, z: Float) {
+ translateMatrix[12] = x
+ translateMatrix[13] = y
+ translateMatrix[14] = z
+
+ mul(translateMatrix)
+ }
+
+ fun scale(x: Float, y: Float, z: Float) {
+ scaleMatrix[0] = x
+ scaleMatrix[5] = y
+ scaleMatrix[10] = z
+
+ mul(scaleMatrix)
+ }
+
+ fun rotateX(angle: Float) {
+ rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+ rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat()
+ rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateXMatrix)
+ }
+
+ fun rotateY(angle: Float) {
+ rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat()
+ rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateYMatrix)
+ }
+
+ fun rotateZ(angle: Float) {
+ rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat()
+ rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateZMatrix)
+ }
+}
diff --git a/src/com/persesgames/net/NetUtils.kt b/src/com/persesgames/net/NetUtils.kt
new file mode 100644
index 0000000..b59cbb3
--- /dev/null
+++ b/src/com/persesgames/net/NetUtils.kt
@@ -0,0 +1,18 @@
+package com.persesgames.net
+
+import org.w3c.xhr.XMLHttpRequest
+
+/**
+ * User: rnentjes
+ * Date: 30-7-16
+ * Time: 16:39
+ */
+
+fun getUrlAsString(url: String): String {
+ val req = XMLHttpRequest()
+
+ req.open("GET", url, false)
+ req.send(null)
+
+ return req.responseText
+}
diff --git a/src/com/persesgames/shader/ShaderProgram.kt b/src/com/persesgames/shader/ShaderProgram.kt
new file mode 100644
index 0000000..3c3aad5
--- /dev/null
+++ b/src/com/persesgames/shader/ShaderProgram.kt
@@ -0,0 +1,110 @@
+package com.persesgames.shader
+
+import org.khronos.webgl.*
+
+/**
+ * User: rnentjes
+ * Date: 17-4-16
+ * Time: 15:15
+ */
+
+class ShaderProgram(
+ val webgl: WebGLRenderingContext,
+ val drawType: Int,
+ vertexShaderSource: String,
+ fragmentShaderSource: String,
+ val vainfo: Array,
+ val setter: (program: ShaderProgram, data: T) -> Unit) {
+
+ var shaderProgram: WebGLProgram
+ var vertex: WebGLShader
+ var fragment: WebGLShader
+
+ var verticesBlockSize = 0
+ var drawLength = 0
+
+ init {
+ vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER)
+ fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER)
+
+ shaderProgram = webgl.createProgram() ?: throw IllegalStateException("Unable to request shader program from webgl context!")
+ webgl.attachShader(shaderProgram, vertex)
+ webgl.attachShader(shaderProgram, fragment)
+ webgl.linkProgram(shaderProgram)
+
+ if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) {
+ println(webgl.getProgramInfoLog(shaderProgram))
+ throw IllegalStateException("Unable to compile shader program!")
+ }
+
+ webgl.useProgram(shaderProgram)
+
+ this.verticesBlockSize = 0;
+
+ // set attribute locations...
+ for (info in vainfo.iterator()) {
+ info.location = webgl.getAttribLocation(shaderProgram, info.locationName)
+ info.offset = verticesBlockSize;
+
+ verticesBlockSize += info.numElements;
+ println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}");
+ }
+
+ when(drawType) {
+ WebGLRenderingContext.TRIANGLES -> {
+ drawLength = verticesBlockSize * 3
+ }
+ else -> {
+ drawLength = verticesBlockSize
+ }
+ }
+
+ println("verticesBlockSize $verticesBlockSize");
+
+ println("ShaderProgram constructor done");
+ }
+
+ private fun compileShader(source: String, type: Int): WebGLShader {
+ val result: WebGLShader
+
+ result = webgl.createShader(type) ?: throw IllegalStateException("Unable to request shader from webgl context!")
+ webgl.shaderSource(result, source)
+ webgl.compileShader(result)
+
+ if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) {
+ throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}")
+ }
+
+ return result
+ }
+
+ fun begin(attribBuffer: WebGLBuffer, userdata: T) {
+ webgl.useProgram(shaderProgram);
+ webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer);
+
+ // set attribute locations...
+ for (info in vainfo.iterator()) {
+ webgl.enableVertexAttribArray(info.location)
+ webgl.vertexAttribPointer(info.location, info.numElements, WebGLRenderingContext.FLOAT, false, verticesBlockSize * 4, info.offset * 4)
+ }
+
+ setter(this, userdata)
+ }
+
+ fun end() {
+ for (info in vainfo.iterator()) {
+ webgl.disableVertexAttribArray(info.location);
+ }
+ webgl.useProgram(null)
+ }
+
+ fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location);
+
+ fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location);
+
+ fun setUniform1f(location: String, value: Float) { webgl.uniform1f(getUniformLocation(location), value); }
+ fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); }
+ fun setUniform1i(location: String, value: Int) { webgl.uniform1i(getUniformLocation(location), value); }
+ fun setUniformMatrix4fv(location: String, value: Float32Array) { webgl.uniformMatrix4fv(getUniformLocation(location), false, value); }
+
+}
diff --git a/src/com/persesgames/shader/ShaderProgramMesh.kt b/src/com/persesgames/shader/ShaderProgramMesh.kt
new file mode 100644
index 0000000..f4c4dd5
--- /dev/null
+++ b/src/com/persesgames/shader/ShaderProgramMesh.kt
@@ -0,0 +1,71 @@
+package com.persesgames.shader
+
+import org.khronos.webgl.Float32Array
+import org.khronos.webgl.WebGLBuffer
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * User: rnentjes
+ * Date: 14-5-16
+ * Time: 11:57
+ */
+
+class VertextAttributeInfo(val locationName: String, val numElements: Int) {
+ var location = 0
+ var offset = 0
+}
+
+class ShaderProgramMesh(
+ val shaderProgram: ShaderProgram
+) {
+ val webgl = shaderProgram.webgl
+ val data: Float32Array
+ var currentIndex: Int = 0
+ val attribBuffer: WebGLBuffer
+ var counter = 0
+
+ init {
+ data = Float32Array(20000 - (20000 % shaderProgram.drawLength))
+
+ attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!")
+ webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer);
+ }
+
+ fun queue(vararg vertices: Float) {
+ queue(vertices as Array)
+ }
+
+ fun queue(vertices: Array) {
+ data.set(vertices, currentIndex)
+ currentIndex += vertices.size
+
+ if (currentIndex == data.length) {
+ println("Skipped draw call, to many values!")
+ currentIndex = 0
+ }
+ }
+
+ fun remaining() = data.length - currentIndex
+
+ fun bufferFull() = currentIndex == data.length
+
+ fun render(userdata: T) {
+ counter++
+ if (currentIndex > 0) {
+/* if (counter % 100 == 0) {
+ println("currentIndex=$currentIndex blockSize=${shaderProgram.verticesBlockSize} drawLength=${shaderProgram.drawLength} drawing=${(currentIndex / shaderProgram.verticesBlockSize).toInt()}")
+ }*/
+ if (currentIndex % shaderProgram.verticesBlockSize != 0) {
+ throw IllegalStateException("Number of vertices not a multiple of the attribute block size!")
+ }
+
+ shaderProgram.begin(attribBuffer, userdata)
+
+ webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW)
+ webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize).toInt())
+ currentIndex = 0
+
+ shaderProgram.end()
+ }
+ }
+}
diff --git a/src/com/persesgames/shooter/Shooter.kt b/src/com/persesgames/shooter/Shooter.kt
deleted file mode 100644
index 864a1b6..0000000
--- a/src/com/persesgames/shooter/Shooter.kt
+++ /dev/null
@@ -1,206 +0,0 @@
-package com.persesgames.shooter
-
-import com.persesgames.game.DrawMode
-import com.persesgames.game.Game
-import com.persesgames.game.Screen
-import com.persesgames.input.EmptyInputProcessor
-import com.persesgames.input.KeyCode
-import com.persesgames.input.Keys
-import com.persesgames.map.tiled.TiledMap
-import com.persesgames.sound.Music
-import com.persesgames.sound.Sounds
-import com.persesgames.sprite.Sprite
-import com.persesgames.sprite.SpriteBatch
-import com.persesgames.text.Texts
-import com.persesgames.texture.Textures
-import org.w3c.dom.HTMLAudioElement
-import org.w3c.dom.HTMLInputElement
-import kotlin.browser.document
-
-/**
- * Created by rnentjes on 19-4-16.
- */
-
-class GameInputProcessor : EmptyInputProcessor() {
-
- override fun keyPressed(charCode: Int) {
- println("charCode: $charCode")
- if (charCode == 32) {
- Sounds.play("EXPLOSION", 0.5f)
- } else if (charCode == 'x'.toInt()) {
- Sounds.play("DROP", 0.75f)
- }
- }
-
- override fun pointerClick(pointer: Int, x: Float, y: Float) {
- println("POINTER $pointer -> ($x, $y)")
- }
-}
-
-var music: HTMLAudioElement? = null
-var showFPS: Boolean = true
-
-class WelcomeScreen : Screen() {
-
- override fun loadResources() {
- println("loading resource!")
-
- //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
-
- Textures.loadSpriteSheet("images/data-0.json")
-
- Keys.setInputProcessor(GameInputProcessor())
- }
-
- override fun update(time: Float, delta: Float) { }
-
- override fun render() {
-
- if (showFPS) {
- Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
- }
- }
-}
-
-class GameScreen : Screen() {
- val map = TiledMap("maps", "level_1_01.json")
-
- var sprites = SpriteBatch()
- var x = 0f
- var y = 15500f
- var sprite = Sprite("SHIP")
- var numberOfSprites: Int = 5000
- var time: Float = 0f
-
- override fun loadResources() {
- Textures.load("SHIP", "images/ship2.png")
-
- Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
- Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
-
- music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
-
- Keys.setInputProcessor(GameInputProcessor())
-
- println("width: ${map.data.width}")
- println("height: ${map.data.height}")
- println("layers: ${map.data.layers?.size}")
-
- val layers = map.data.layers
- if (layers != null) {
- println("layer0: ${layers[0].name}")
- }
- val tilesets = map.data.tilesets
- if (tilesets != null) {
- println("tilesets ${tilesets.size}")
- println("tileset0: ${tilesets[0].name}")
- }
- }
-
- override fun update(time: Float, delta: Float) {
- this.time = time
- val speed = 1500f // units per second
-
- if (Keys.isDown(KeyCode.LEFT)) {
- x -= delta * speed
- println("x=$x")
- }
-
- if (Keys.isDown(KeyCode.RIGHT)) {
- x += delta * speed
- println("x=$x")
- }
-
- if (Keys.isDown(KeyCode.UP)) {
- y += delta * speed
- println("y=$y")
- }
-
- if (Keys.isDown(KeyCode.DOWN)) {
- y -= delta * speed
- println("y=$y")
- }
-
- if (Keys.isDown(KeyCode.MINUS)) {
- if (numberOfSprites > 25) {
- numberOfSprites = (numberOfSprites * 0.9f).toInt()
- }
- }
-
- if (Keys.isDown(KeyCode.PLUS)) {
- numberOfSprites = (numberOfSprites * 1.1f).toInt()
- }
- }
-
- override fun render() {
- var r = 0f
- var d = 0f
- var x = 0f
- var y = 0f
-
- map.drawLayer(1, this.x, this.y)
- map.drawLayer(2, this.x, this.y)
-
- val time = this.time / 10f
- for (index in 0..numberOfSprites) {
- r = index * 0.05f
- d = index * 2.13f
- x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
- y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
-
- sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
- }
-
- sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
-
- sprites.render()
-
- Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
-
- if (showFPS) {
- Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
- Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
- }
- }
-
-}
-
-fun main(args: Array) {
- Game.view.setToHeight(1000f)
- Game.view.drawMode = DrawMode.LINEAR
-
- Game.view.minAspectRatio = 0.9f
- Game.view.maxAspectRatio = 1.5f
-
- Game.start(WelcomeScreen())
-}
-
-fun changeMusic(it: HTMLInputElement) {
- val mus = music
-
- if (mus != null) {
- if (it.checked) {
- mus.volume = 0.5
- } else {
- mus.volume = 0.0
- }
- }
-}
-
-fun showFPS(it: HTMLInputElement) {
- showFPS = it.checked
-}
-
-fun pause(it: HTMLInputElement) {
- Game.pause = it.checked
-}
-
-fun playGame() {
- document.getElementById("menu")?.setAttribute("style", "display: none;")
-
- Game.setScreen(GameScreen())
-}
-
-fun fullscreen() {
- Game.view.requestFullscreen()
-}
diff --git a/src/com/persesgames/sound/Music.kt b/src/com/persesgames/sound/Music.kt
new file mode 100644
index 0000000..88a531d
--- /dev/null
+++ b/src/com/persesgames/sound/Music.kt
@@ -0,0 +1,49 @@
+package com.persesgames.sound
+
+import org.w3c.dom.HTMLAudioElement
+import java.util.*
+import kotlin.browser.document
+import kotlin.dom.on
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 13:02
+ */
+
+object Music {
+ val playing: MutableSet = HashSet()
+
+ fun load(url: String): HTMLAudioElement {
+ val audio = document.createElement("audio") as HTMLAudioElement
+
+ audio.src = url
+
+ return audio;
+ }
+
+ fun play(url: String, volume: Double = 0.75, looping: Boolean = false): HTMLAudioElement {
+ val audio = document.createElement("audio") as HTMLAudioElement
+
+ audio.src = url
+ audio.volume = volume
+ audio.play()
+
+ audio.on("ended", true, {
+ if (looping) {
+ audio.currentTime = 0.0
+ audio.play()
+ } else {
+ println("REMOVING: $audio")
+ audio.remove()
+ playing.remove(audio)
+ }
+ })
+
+ return audio
+ }
+
+ fun stopAll() {
+
+ }
+}
diff --git a/src/com/persesgames/sound/Sounds.kt b/src/com/persesgames/sound/Sounds.kt
new file mode 100644
index 0000000..8d8c549
--- /dev/null
+++ b/src/com/persesgames/sound/Sounds.kt
@@ -0,0 +1,62 @@
+package com.persesgames.sound
+
+import org.w3c.dom.HTMLAudioElement
+import java.util.*
+import kotlin.browser.document
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 12:34
+ */
+
+class Sound(val name:String, val url: String, val volume: Double = 0.75, val numberOfChannels: Int) {
+ var channels: Array
+ var nextChannel: Int = 0
+
+ init {
+ println("CREATING: $name")
+ channels = Array(numberOfChannels, { document.createElement("audio") as HTMLAudioElement })
+
+ for (audio in channels) {
+ audio.src = url
+ audio.pause()
+ audio.load()
+ audio.volume = volume
+ }
+ }
+
+ fun play() {
+ println("PLAYING: $name - $nextChannel")
+ channels[nextChannel].currentTime = 0.0
+ channels[nextChannel].play()
+
+ nextChannel = (nextChannel + 1) % channels.size
+ }
+
+ fun pause() {
+ for (audio in channels) {
+ audio.pause()
+ }
+ }
+}
+
+object Sounds {
+ val sounds: MutableMap = HashMap()
+
+ fun load(name: String, url: String, volume: Double = 0.75, channels: Int = 1 ) {
+ sounds.put(name, Sound(name, url, volume, channels))
+ }
+
+ fun play(name: String, volume: Float = 0.75f) {
+ val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!")
+
+ sound.play()
+ }
+
+ fun pause(name: String) {
+ val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!")
+
+ sound.pause()
+ }
+}
diff --git a/src/com/persesgames/sprite/SpriteBatch.kt b/src/com/persesgames/sprite/SpriteBatch.kt
new file mode 100644
index 0000000..8f72f31
--- /dev/null
+++ b/src/com/persesgames/sprite/SpriteBatch.kt
@@ -0,0 +1,26 @@
+package com.persesgames.sprite
+
+import com.persesgames.texture.Texture
+import com.persesgames.texture.Textures
+
+/**
+ * User: rnentjes
+ * Date: 20-4-16
+ * Time: 13:48
+ */
+
+class Sprite(val textureName: String) {
+ val texture: Texture by lazy { Textures.get(textureName) }
+}
+
+class SpriteBatch {
+
+ fun draw(sprite: Sprite, x: Float, y: Float, scale: Float = 1f, rotation: Float = 0f) {
+ sprite.texture.queueDraw(x, y, scale, rotation)
+ }
+
+ fun render() {
+ Textures.render()
+ }
+
+}
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_test.iml b/.idea/modules/kotlin-webgl-test_test.iml
deleted file mode 100644
index 6ac62a6..0000000
--- a/.idea/modules/kotlin-webgl-test_test.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kudens.iml b/.idea/modules/kudens.iml
new file mode 100644
index 0000000..bb33e4b
--- /dev/null
+++ b/.idea/modules/kudens.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_main.iml b/.idea/modules/kudens_main.iml
new file mode 100644
index 0000000..70f44bd
--- /dev/null
+++ b/.idea/modules/kudens_main.iml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kudens_test.iml b/.idea/modules/kudens_test.iml
new file mode 100644
index 0000000..4b8ee03
--- /dev/null
+++ b/.idea/modules/kudens_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 77041ff..4562616 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,16 @@
apply plugin: 'kotlin2js'
apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'maven-publish'
+
+idea {
+ module {
+ name = "kudens"
+ }
+}
sourceSets {
- main.kotlin.srcDirs += 'lib/kotludens'
main.kotlin.srcDirs += 'src'
}
@@ -17,7 +24,7 @@
}
buildscript {
- ext.kotlin_version = '1.0.6'
+ ext.kotlin_version = '1.1.0-beta-18'
repositories {
maven {
url "http://nexus.astraeus.nl/nexus/content/groups/public"
@@ -35,36 +42,63 @@
task jarSources(type:Jar){
from sourceSets.main.allSource
+
classifier = 'source'
}
+
artifacts {
compile jarSources
}
-def outDir = "${buildDir}/kotlin2js/main/"
-
compileKotlin2Js {
kotlinOptions.metaInfo = true
compileKotlin2Js.kotlinOptions.sourceMap = true
- compileKotlin2Js.kotlinOptions.outputFile = "${projectDir}/web/js/generated/KotlinTest.js"
+ compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlinjs/kudens.js"
compileKotlin2Js.kotlinOptions.suppressWarnings = true
compileKotlin2Js.kotlinOptions.verbose = true
}
-jar {
- from sourceSets.main.allSource
- include "**/*.kt"
+def outDir = "${buildDir}/kotlinjs/"
+jar {
from outDir
include "**/*.js"
manifest {
attributes(
- "Specification-Title": "Kotlin JavaScript Lib",
- "Kotlin-JS-Module-Name": "test-library"
+ "Specification-Title": "Kudens game lib",
+ "Kotlin-JS-Module-Name": "lib-kudens"
)
}
}
-jar.dependsOn(compileKotlin2Js)
\ No newline at end of file
+jar.dependsOn(compileKotlin2Js)
+
+build.doLast {
+ configurations.compile.each { File file ->
+ copy {
+ includeEmptyDirs = false
+
+ from zipTree(file.absolutePath)
+ into "${projectDir}/web"
+ include { fileTreeElement ->
+ def path = fileTreeElement.path
+ path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
+ }
+ }
+ }
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
+ authentication(userName: nexusUsername, password: nexusPassword)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0515d59..39bba2b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 20 20:26:54 CEST 2015
+#Sat Jan 21 15:59:58 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
index 0d4593c..a84a5a3 100644
--- a/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
+++ b/lib/kotludens/com/persesgames/map/tiled/TiledMap.kt
@@ -194,14 +194,18 @@
}
}
- for (tileset in data.tilesets) {
- if (Textures.has(tileset.name)) {
- val tx = Textures.get(tileset.name)
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
- tx.render()
+ tx.render()
+ }
}
}
+
first = false
}
}
diff --git a/lib/kotludens/com/persesgames/texture/Textures.kt b/lib/kotludens/com/persesgames/texture/Textures.kt
index db24963..24840b6 100644
--- a/lib/kotludens/com/persesgames/texture/Textures.kt
+++ b/lib/kotludens/com/persesgames/texture/Textures.kt
@@ -81,16 +81,12 @@
val width: Int,
val height: Int
) {
- val shaderProgramMesh: ShaderProgramMesh
+ val shaderProgramMesh: ShaderProgramMesh = ShaderProgramMesh(shaderProgram)
val left = -width / 2f
val right = width / 2f
val bottom = -height / 2f
val top = height / 2f
- init {
- shaderProgramMesh = ShaderProgramMesh(shaderProgram)
- }
-
fun queueDraw(x: Float, y: Float, scale: Float, rotation: Float) {
shaderProgramMesh.queue( x, y, left, bottom, 0f, 0f, scale, rotation)
shaderProgramMesh.queue( x, y, left, top, 0f, 1f, scale, rotation)
diff --git a/lib/kotludens/shooter/Shooter.kt b/lib/kotludens/shooter/Shooter.kt
new file mode 100644
index 0000000..a02c911
--- /dev/null
+++ b/lib/kotludens/shooter/Shooter.kt
@@ -0,0 +1,205 @@
+package com.persesgames.shooter
+
+import com.persesgames.game.DrawMode
+import com.persesgames.game.Game
+import com.persesgames.game.Screen
+import com.persesgames.input.EmptyInputProcessor
+import com.persesgames.input.KeyCode
+import com.persesgames.input.Keys
+import com.persesgames.map.tiled.TiledMap
+import com.persesgames.sound.Music
+import com.persesgames.sound.Sounds
+import com.persesgames.sprite.Sprite
+import com.persesgames.sprite.SpriteBatch
+import com.persesgames.text.Texts
+import com.persesgames.texture.Textures
+import org.w3c.dom.HTMLAudioElement
+import org.w3c.dom.HTMLInputElement
+import kotlin.browser.document
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+class GameInputProcessor : EmptyInputProcessor() {
+
+ override fun keyPressed(charCode: Int) {
+ println("charCode: $charCode")
+ if (charCode == 32) {
+ Sounds.play("EXPLOSION", 0.5f)
+ } else if (charCode == 'x'.toInt()) {
+ Sounds.play("DROP", 0.75f)
+ }
+ }
+
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ println("POINTER $pointer -> ($x, $y)")
+ }
+}
+
+var music: HTMLAudioElement? = null
+var showFPS: Boolean = true
+
+class WelcomeScreen : Screen() {
+
+ override fun loadResources() {
+ println("loading resource!")
+
+ //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
+
+ Textures.loadSpriteSheet("images/data-0.json")
+
+ Keys.setInputProcessor(GameInputProcessor())
+ }
+
+ override fun update(time: Float, delta: Float) { }
+
+ override fun render() {
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
+ }
+ }
+}
+
+class GameScreen : Screen() {
+ val map = TiledMap("maps", "level_1_01.json")
+
+ var sprites = SpriteBatch()
+ var x = 0f
+ var y = 15500f
+ var sprite = Sprite("SHIP")
+ var numberOfSprites: Int = 5000
+ var time: Float = 0f
+
+ override fun loadResources() {
+ Textures.load("SHIP", "images/ship2.png")
+
+ Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
+ Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
+
+ music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
+
+ Keys.setInputProcessor(GameInputProcessor())
+
+ println("width: ${map.data.width}")
+ println("height: ${map.data.height}")
+ println("layers: ${map.data.layers?.size}")
+
+ val layers = map.data.layers
+ if (layers != null) {
+ println("layer0: ${layers[0].name}")
+ }
+ val tilesets = map.data.tilesets
+ if (tilesets != null) {
+ println("tilesets ${tilesets.size}")
+ println("tileset0: ${tilesets[0].name}")
+ }
+ }
+
+ override fun update(time: Float, delta: Float) {
+ this.time = time
+ val speed = 1500f // units per second
+
+ if (Keys.isDown(KeyCode.LEFT)) {
+ x -= delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.RIGHT)) {
+ x += delta * speed
+ println("x=$x")
+ }
+
+ if (Keys.isDown(KeyCode.UP)) {
+ y += delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.DOWN)) {
+ y -= delta * speed
+ println("y=$y")
+ }
+
+ if (Keys.isDown(KeyCode.MINUS)) {
+ if (numberOfSprites > 25) {
+ numberOfSprites = (numberOfSprites * 0.9f).toInt()
+ }
+ }
+
+ if (Keys.isDown(KeyCode.PLUS)) {
+ numberOfSprites = (numberOfSprites * 1.1f).toInt()
+ }
+ }
+
+ override fun render() {
+ var r = 0f
+ var d = 0f
+ var x = 0f
+ var y = 0f
+
+ map.drawLayer(1, this.x, this.y)
+ map.drawLayer(2, this.x, this.y)
+
+ val time = this.time / 10f
+ for (index in 0..numberOfSprites) {
+ r = index * 0.05f
+ d = index * 2.13f
+ x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
+ y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
+
+ sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
+ }
+
+ sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
+
+ sprites.render()
+
+ Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
+
+ if (showFPS) {
+ Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
+ Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
+ }
+ }
+}
+
+fun main(args: Array) {
+ Game.view.setToHeight(1000f)
+ Game.view.drawMode = DrawMode.LINEAR
+
+ Game.view.minAspectRatio = 0.9f
+ Game.view.maxAspectRatio = 1.5f
+
+ Game.start(WelcomeScreen())
+}
+
+fun changeMusic(it: HTMLInputElement) {
+ val mus = music
+
+ if (mus != null) {
+ if (it.checked) {
+ mus.volume = 0.5
+ } else {
+ mus.volume = 0.0
+ }
+ }
+}
+
+fun showFPS(it: HTMLInputElement) {
+ showFPS = it.checked
+}
+
+fun pause(it: HTMLInputElement) {
+ Game.pause = it.checked
+}
+
+fun playGame() {
+ document.getElementById("menu")?.setAttribute("style", "display: none;")
+
+ Game.setScreen(GameScreen())
+}
+
+fun fullscreen() {
+ Game.view.requestFullscreen()
+}
diff --git a/settings.gradle b/settings.gradle
index 329f712..3181c92 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-rootProject.name = 'kotlin-webgl-test'
+rootProject.name = 'kudens'
diff --git a/src/com/persesgames/game/Game.kt b/src/com/persesgames/game/Game.kt
new file mode 100644
index 0000000..3abdd56
--- /dev/null
+++ b/src/com/persesgames/game/Game.kt
@@ -0,0 +1,155 @@
+package com.persesgames.game
+
+import com.persesgames.texture.Textures
+import org.khronos.webgl.WebGLRenderingContext
+import org.w3c.dom.CanvasRenderingContext2D
+import org.w3c.dom.HTMLCanvasElement
+import org.w3c.dom.HTMLElement
+import kotlin.browser.document
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+enum class DrawMode {
+ LINEAR,
+ NEAREST
+}
+
+class HTMLElements {
+ var container: HTMLElement
+ var webgl: WebGLRenderingContext
+ var canvas2d: CanvasRenderingContext2D
+
+ init {
+ container = document.createElement("div") as HTMLElement
+
+ val webGlCanvas = document.createElement("canvas") as HTMLCanvasElement
+ val canvas = document.createElement("canvas") as HTMLCanvasElement
+
+ container.setAttribute("style", "position: absolute; left: 0px; top: 0px;")
+ webGlCanvas.setAttribute("style", "position: absolute; left: 0px; top: 0px;" )
+ canvas.setAttribute("style", "position: absolute; left: 0px; top: 0px; z-index: 10; width: 1000px; height: 500px;" )
+
+ document.body!!.appendChild(container)
+ container.appendChild(webGlCanvas)
+ container.appendChild(canvas)
+
+ webgl = webGlCanvas.getContext("webgl") as WebGLRenderingContext
+ canvas2d = canvas.getContext("2d") as CanvasRenderingContext2D
+ }
+}
+
+object Game {
+ var started = false
+ val view: View = View()
+ val html: HTMLElements by lazy { HTMLElements() }
+ var currentScreen: Screen = DefaultScreen()
+ var start = Date().getTime()
+ var currentTime = start
+ var currentDelta = 0f
+ var pause: Boolean = false
+
+ var fps = 0
+ var fpsCount = 0
+ var fpsCountTime = 0f
+
+ fun gl() = html.webgl
+
+ fun resize() {
+ val canvas = gl().canvas
+
+ // Check if the canvas is not the same size.
+ val windowWidth = window.innerWidth.toInt()
+ val windowHeight = window.innerHeight.toInt()
+
+ if (view.lastWindowWidth != windowWidth ||
+ view.lastWindowHeight != windowHeight) {
+ view.lastWindowWidth = windowWidth
+ view.lastWindowHeight = windowHeight
+ view.windowWidth = windowWidth
+ view.windowHeight = windowHeight
+
+ view.updateView()
+
+ val textCanvas = html.canvas2d.canvas
+
+ // Make the canvas the same size
+ canvas.width = view.width.toInt()
+ canvas.height = view.height.toInt()
+
+ textCanvas.width = view.width.toInt()
+ textCanvas.height = view.height.toInt()
+
+ gl().viewport(0, 0, view.width.toInt(), view.height.toInt())
+
+ val left = (windowWidth - view.windowWidth) / 2
+ val top = (windowHeight - view.windowHeight) / 2
+
+ canvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 5; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ textCanvas.setAttribute("style", "position: absolute; left: ${left}px; top: ${top}px; z-index: 10; width: ${view.windowWidth}px; height: ${view.windowHeight}px;" )
+ }
+ }
+
+ fun start(startScreen: Screen) {
+ if (started) {
+ throw IllegalStateException("You can only start a game once!")
+ }
+
+ setScreen(startScreen)
+
+ // start game loop
+ started = true
+ gameLoop()
+ }
+
+ fun setScreen(screen: Screen) {
+ currentScreen.closeResources()
+
+ currentScreen = screen
+
+ currentScreen.loadResources()
+ }
+
+ fun gameLoop() {
+ if (!Textures.ready()) {
+ Game.gl().clearColor(1f, 1f, 1f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ } else {
+ resize()
+
+ if (!pause) {
+ html.canvas2d.clearRect(0.0, 0.0, view.width.toDouble(), view.height.toDouble());
+
+ Game.gl().clearColor(0f, 0f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+
+ Game.gl().enable(WebGLRenderingContext.BLEND);
+ Game.gl().blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA); //ONE_MINUS_DST_ALPHA);
+
+ val time = Date().getTime()
+ currentDelta = (time - currentTime) / 1000f
+ currentTime = time
+
+ val timeInSeconds = (currentTime - start) / 1000f
+
+ fpsCountTime += currentDelta
+ fpsCount++
+ while (fpsCountTime > 1f) {
+ fps = fpsCount
+ fpsCountTime -= 1f
+ fpsCount = 0
+ }
+
+ currentScreen.update(timeInSeconds, currentDelta);
+ currentScreen.render()
+ }
+ }
+
+ window.requestAnimationFrame {
+ gameLoop()
+ }
+ }
+
+}
diff --git a/src/com/persesgames/game/Screen.kt b/src/com/persesgames/game/Screen.kt
new file mode 100644
index 0000000..6fb558e
--- /dev/null
+++ b/src/com/persesgames/game/Screen.kt
@@ -0,0 +1,35 @@
+package com.persesgames.game
+
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * Created by rnentjes on 19-4-16.
+ */
+
+abstract class Screen {
+
+ open fun loadResources() {
+
+ }
+
+ open fun closeResources() {
+
+ }
+
+ abstract fun update(time: Float, delta: Float)
+
+ abstract fun render()
+
+}
+
+
+class DefaultScreen: Screen() {
+ override fun update(time: Float, delta: Float) {
+ }
+
+ override fun render() {
+ // show loading message?
+ Game.gl().clearColor(1f, 1f, 0f, 1f)
+ Game.gl().clear(WebGLRenderingContext.COLOR_BUFFER_BIT)
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/game/View.kt b/src/com/persesgames/game/View.kt
new file mode 100644
index 0000000..e5590e0
--- /dev/null
+++ b/src/com/persesgames/game/View.kt
@@ -0,0 +1,221 @@
+package com.persesgames.game
+
+import com.persesgames.math.Matrix4
+
+enum class ViewType {
+ PROJECTION,
+ WIDTH,
+ HEIGHT,
+ ABSOLUTE
+}
+
+class View(
+ var lastWindowWidth: Int = 2000,
+ var lastWindowHeight: Int = 1000,
+ var windowWidth: Int = 2000,
+ var windowHeight: Int = 1000,
+ var width: Float = 1024f,
+ var height: Float = 1024f,
+ var angle: Float = 60f,
+ var near: Float = -0.1f,
+ var far: Float = -100f,
+ var minAspectRatio: Float = 1f,
+ var maxAspectRatio: Float = 1f,
+ var leftOffset: Int = 0,
+ var bottomOffset: Int = 0,
+ var viewType: ViewType = ViewType.WIDTH,
+ var drawMode: DrawMode = DrawMode.LINEAR) {
+ var vMatrix = Matrix4()
+ var aspectRatio = 1f
+
+ init {
+ updateView()
+ }
+
+ fun requestFullscreen() {
+ println("Requesting fullscreen")
+ js("""
+ if (document.webkitFullscreenElement) {
+ document.webkitCancelFullScreen();
+ } else {
+ document.documentElement.webkitRequestFullScreen();
+ }
+ """)
+ //if (document.fullscreenEnabled) {
+ // println("fullscreen Enabled")
+ //Game.html.container.requestFullscreen()
+ //document.documentElement?.requestFullscreen()
+ //}
+ }
+
+ fun updateView() {
+ aspectRatio = windowWidth / windowHeight.toFloat()
+
+ if (aspectRatio < minAspectRatio) {
+ aspectRatio = minAspectRatio
+
+ windowHeight = (windowWidth / aspectRatio).toInt()
+ }
+
+ if (aspectRatio > maxAspectRatio) {
+ aspectRatio = maxAspectRatio
+
+ windowWidth = (windowHeight * aspectRatio).toInt()
+ }
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.WIDTH -> {
+ height = width / aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.HEIGHT -> {
+ width = height * aspectRatio
+
+ vMatrix.setOrthographicProjection(0f, width, 0f, height, near, far)
+ }
+ ViewType.PROJECTION -> {
+ vMatrix.setPerspectiveProjection(angle, aspectRatio, near, far);
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ //println("width: $width, height: $height")
+ }
+
+ fun screenToGameCoordX(screenX: Float): Float {
+ var result = screenX
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.HEIGHT -> {
+ result = (screenX / windowWidth * width) - width / 2
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun screenToGameCoordY(screenY: Float): Float {
+ var result = screenY
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.HEIGHT -> {
+ result = -((screenY / windowHeight * height) - height / 2)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordX(gameX: Float): Float {
+ var result = gameX
+ val normalizedX = gameX + (width / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.HEIGHT -> {
+ result = (windowWidth / width * normalizedX)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun gameToScreenCoordY(gameY: Float): Float {
+ var result = gameY
+ val normalizedY = gameY + (height / 2)
+
+ when (viewType) {
+ ViewType.ABSOLUTE -> {
+ // nop
+ }
+ ViewType.WIDTH -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.HEIGHT -> {
+ result = windowHeight - (windowHeight / height * normalizedY)
+ }
+ ViewType.PROJECTION -> {
+ // uhm
+ }
+ else -> {
+ throw IllegalStateException("ViewType $viewType not implemented!")
+ }
+ }
+
+ return result
+ }
+
+ fun setToWidth(width: Float) {
+ this.width = width
+ this.viewType = ViewType.WIDTH
+
+ updateView()
+ }
+
+ fun setToHeight(height: Float) {
+ this.height = height
+ this.viewType = ViewType.HEIGHT
+
+ updateView()
+ }
+
+ fun setProjection(angle: Float) {
+ this.angle = angle
+ this.viewType = ViewType.PROJECTION
+
+ updateView()
+ }
+
+ fun setNear(near: Float) {
+ this.near = near
+
+ updateView()
+ }
+
+ fun setFar(far: Float) {
+ this.far = far
+
+ updateView()
+ }
+}
\ No newline at end of file
diff --git a/src/com/persesgames/input/Keys.kt b/src/com/persesgames/input/Keys.kt
new file mode 100644
index 0000000..6705c67
--- /dev/null
+++ b/src/com/persesgames/input/Keys.kt
@@ -0,0 +1,141 @@
+package com.persesgames.input
+
+import com.persesgames.game.Game
+import org.w3c.dom.events.Event
+import org.w3c.dom.events.KeyboardEvent
+import org.w3c.dom.events.MouseEvent
+import java.util.*
+import kotlin.browser.document
+import kotlin.dom.on
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 12:18
+ */
+
+enum class KeyCode(val keyCode: Int) {
+ LEFT(37),
+ UP(38),
+ DOWN(40),
+ RIGHT(39),
+ SPACE(32),
+ MINUS(109),
+ PLUS(107),
+}
+
+interface InputProcessor {
+
+ fun keyPressed(charCode: Int)
+
+ fun keyDown(keyCode: Int)
+
+ fun keyUp(keyCode: Int)
+
+ fun pointerClick(pointer: Int, x: Float, y: Float)
+
+}
+
+open class EmptyInputProcessor : InputProcessor {
+ override fun pointerClick(pointer: Int, x: Float, y: Float) {
+ }
+
+ override fun keyDown(keyCode: Int) {
+ }
+
+ override fun keyPressed(charCode: Int) {
+ }
+
+ override fun keyUp(keyCode: Int) {
+ }
+
+
+}
+
+object Keys {
+
+ private val keys: MutableMap = HashMap();
+ private var inputProcesser: InputProcessor = EmptyInputProcessor()
+
+ init {
+ val body = document.body
+ if (body != null) {
+ body.on("keydown", true) {
+ Keys.keyDown(it)
+ }
+
+ body.on("keyup", true) {
+ Keys.keyUp(it)
+ }
+
+ body.on("keypress", true) {
+ Keys.keyPress(it)
+ }
+
+ body.on("click", true) {
+ Keys.mouseClick(it)
+ }
+
+ body.on("mousedown", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mouseup", true) {
+ Keys.mouseMove(it)
+ }
+
+ body.on("mousemove", true) {
+ Keys.mouseMove(it)
+ }
+ }
+ }
+
+ fun setInputProcessor(processor: InputProcessor) {
+ this.inputProcesser = processor
+ }
+
+ private fun keyDown(key: Event) {
+ if (key is KeyboardEvent) {
+ keys.put(key.keyCode, Date().getTime())
+
+ inputProcesser.keyDown(key.keyCode)
+ }
+ }
+
+ private fun keyUp(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyUp(key.keyCode)
+
+ keys.remove(key.keyCode)
+ }
+ }
+
+ private fun keyPress(key: Event) {
+ if (key is KeyboardEvent) {
+ inputProcesser.keyPressed(key.charCode)
+ }
+ }
+
+ private fun mouseClick(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+ inputProcesser.pointerClick(event.button.toInt(), vx, vy)
+ }
+ }
+
+ private fun mouseMove(event: Event) {
+ if (event is MouseEvent) {
+ val vx: Float = Game.view.screenToGameCoordX(event.clientX.toFloat())
+ val vy: Float = Game.view.screenToGameCoordY(event.clientY.toFloat())
+
+
+ }
+ }
+
+ fun isDown(keyCode: Int) = keys.containsKey(keyCode)
+
+ fun isDown(keyCode: KeyCode) = keys.containsKey(keyCode.keyCode)
+
+}
diff --git a/src/com/persesgames/map/Map.kt b/src/com/persesgames/map/Map.kt
new file mode 100644
index 0000000..b5d7bc8
--- /dev/null
+++ b/src/com/persesgames/map/Map.kt
@@ -0,0 +1,9 @@
+package com.persesgames.map
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+open class Map {
+
+}
diff --git a/src/com/persesgames/map/tiled/TiledMap.kt b/src/com/persesgames/map/tiled/TiledMap.kt
new file mode 100644
index 0000000..a84a5a3
--- /dev/null
+++ b/src/com/persesgames/map/tiled/TiledMap.kt
@@ -0,0 +1,211 @@
+package com.persesgames.map.tiled
+
+import com.persesgames.net.getUrlAsString
+import com.persesgames.texture.Texture
+import com.persesgames.texture.Textures
+import java.util.*
+import kotlin.browser.window
+
+/**
+ * Created by rnentjes on 22-7-16.
+ */
+
+class MapData {
+ var version: Int = 1
+ var properties: MutableMap = HashMap()
+ var layers: Array? = null
+ var tilesets: Array? = null
+
+ var height: Int = 0
+ var width: Int = 0
+
+ var nextobjectid: Int = 0
+ var orientation: String = "orthogonal"
+ var renderorder: String = "right-down"
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+}
+
+class MapLayer {
+ var properties: MutableMap = HashMap()
+
+ var data: Array? = null
+ var encoding: String = ""
+ var x: Int = 0
+ var y: Int = 0
+ var width: Int = 0
+ var height: Int = 0
+ var name: String = ""
+ var opacity: Float = 1f
+ var type: String = ""
+ var visible: Boolean = true
+ var draworder: String = ""
+}
+
+class MapTileset {
+ var properties: MutableMap = HashMap()
+
+ var firstgid: Int = 0
+ var image: String = ""
+ var imageheight: Int = 0
+ var imagewidth: Int = 0
+ var margin: Int = 0
+ var name: String = ""
+ var spacing: Int = 0
+ var tilecount: Int = 0
+ var tileheight: Int = 0
+ var tilewidth: Int = 0
+ var tileproperties: MutableMap> = HashMap()
+}
+
+class TilesetIndex(
+ val texture: Texture?,
+ val tcLeft: Float,
+ val tcTop: Float,
+ val tcRight: Float,
+ val tcBottom: Float,
+ val scale: Float
+ ) {
+ constructor() : this(null, 0f, 0f, 0f, 0f, 0f)
+
+ fun render(x: Float, y: Float) {
+ texture?.queueTileDraw(x, y, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+}
+
+class TiledMap(dir: String = "", url: String) {
+ val properties: Map = HashMap()
+ val data: MapData
+ val tileset: Array
+ val tiles: Array
+ var first = true
+ //var tilesetIndex: Array = Array(0, { TilesetIndex() })
+
+ init {
+ var tileDir = dir
+ if (!tileDir.isEmpty() && !tileDir.endsWith("/")) {
+ tileDir = tileDir + "/"
+ }
+
+ data = JSON.parse(getUrlAsString(tileDir + url))
+ println("map data is loaded")
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ tileset = Array(tilesets.size, { "" })
+ var maxGid = 0
+ for (index in 0..tilesets.size - 1) {
+ tileset[index] = tilesets[index].name
+ Textures.load(tilesets[index].name, tileDir + tilesets[index].image)
+ maxGid = Math.max(maxGid, tilesets[index].firstgid + tilesets[index].tilecount)
+ }
+
+ tiles = Array(maxGid, { TilesetIndex() })
+ } else {
+ tileset = Array(0, { "" })
+ tiles = Array(0, { TilesetIndex() })
+ }
+
+ cacheTiles()
+ }
+
+ fun cacheTiles() {
+ if (!Textures.ready()) {
+ window.setTimeout({ cacheTiles() }, 10)
+ } else {
+ val tilesets = data.tilesets
+ var tcLeft = 0f
+ var tcTop = 0f
+ var tcRight = 0f
+ var tcBottom = 0f
+
+ if (tilesets != null) {
+
+
+ for (tileset in tilesets) {
+ val tilesHor = tileset.imagewidth / tileset.tilewidth
+ val tilesVer = tileset.imageheight / tileset.tileheight
+ val scale = (tileset.tilewidth / tileset.imagewidth.toFloat())
+
+ for (index in tileset.firstgid..tileset.firstgid + tileset.tilecount) {
+ val texture = Textures.get(tileset.name)
+
+ val gid = index - tileset.firstgid
+
+ val xi = gid % tilesHor
+ var yi = gid / tilesHor
+ yi = tilesVer - yi - 1
+ val tw = 1f / tilesHor.toFloat()
+ val th = 1f / tilesVer.toFloat()
+
+ val pixelW = 0.1f / tileset.tilewidth
+ val pixelH = 0.1f / tileset.tileheight
+
+ tcLeft = xi * tw
+ tcRight = tcLeft + tw
+
+ // switch up/down because of texture coord 0,0 in left bottom corner
+ tcBottom = yi * th
+ tcTop = tcBottom + th
+
+ tcLeft += pixelW
+ tcRight -= pixelW
+
+ tcBottom += pixelH
+ tcTop -= pixelH
+
+ tiles[index] = TilesetIndex(texture, tcLeft, tcTop, tcRight, tcBottom, scale)
+ }
+ }
+ }
+ }
+ }
+
+ fun drawTile(tile: Int, x: Float, y: Float) {
+ tiles[tile].render(x, y)
+ }
+
+ fun drawLayer(layerIndex: Int, xo: Float, yo: Float) {
+ var x = 0f
+ var y = 0f
+ val layers = data.layers ?: throw IllegalArgumentException("MapData has no layers ($data)")
+ val layer = layers[layerIndex]
+
+ val layerData = layer.data
+ if (layerData != null) {
+ for (index in layerData.indices) {
+ // todo: determine if in view
+ // todo: determine tilewidth
+ //if (xo+x*128f < Game.view.width && yo + y * 128 < Game.view.height) {
+ drawTile(layerData[index], xo + x * 128f, yo + y * 128f)
+
+ when (data.renderorder) {
+ "right-down" -> {
+ x++
+ if (x >= layer.width) {
+ x = 0f
+ y--
+ }
+ }
+ else -> {
+ throw IllegalStateException("Renderorder ${data.renderorder} not supported in $this")
+ }
+ }
+ //}
+ }
+ }
+
+ val tilesets = data.tilesets
+ if (tilesets != null) {
+ for (tileset in tilesets) {
+ if (Textures.has(tileset.name)) {
+ val tx = Textures.get(tileset.name)
+
+ tx.render()
+ }
+ }
+ }
+
+
+ first = false
+ }
+}
diff --git a/src/com/persesgames/math/Matrix4.kt b/src/com/persesgames/math/Matrix4.kt
new file mode 100644
index 0000000..3cb4ed4
--- /dev/null
+++ b/src/com/persesgames/math/Matrix4.kt
@@ -0,0 +1,192 @@
+package com.persesgames.math
+
+import org.khronos.webgl.Float32Array
+
+/**
+ * User: rnentjes
+ * Date: 17-4-16
+ * Time: 15:43
+ */
+class Matrix4 {
+
+ internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ internal var temp = FloatArray(16)
+
+ private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
+
+ fun get(): FloatArray {
+ return matrix
+ }
+
+ fun getFloat32Array() = Float32Array(get().toTypedArray())
+
+ fun set(values: FloatArray) {
+ if (values.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ matrix = values
+ }
+
+ fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) {
+ val r = (angle / 180f * Math.PI).toFloat()
+ val f = (1.0f / Math.tan((r / 2.0f).toDouble())).toFloat()
+
+ matrix[0] = f / imageAspectRatio
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+
+ matrix[4] = 0.0f
+ matrix[5] = f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = -(far + near) / (far - near)
+ matrix[11] = -1.0f
+
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = -(2.0f * far * near) / (far - near)
+ matrix[15] = 0.0f
+ }
+
+ fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) {
+ matrix[0] = 2f / (right - left)
+ matrix[1] = 0f
+ matrix[2] = 0f
+ matrix[3] = 0f
+
+ matrix[4] = 0f
+ matrix[5] = 2f / (top - bottom)
+ matrix[6] = 0f
+ matrix[7] = 0f
+
+ matrix[8] = 0f
+ matrix[9] = 0f
+ matrix[10] = -2f / (far - near)
+ matrix[11] = 0f
+
+ matrix[12] = - (right + left) / (right - left)
+ matrix[13] = - (top + bottom) / (top - bottom)
+ matrix[14] = - (far + near) / (far - near)
+ matrix[15] = 1f
+ }
+
+ fun setToIdentity() {
+ matrix[0] = 1.0f
+ matrix[1] = 0.0f
+ matrix[2] = 0.0f
+ matrix[3] = 0.0f
+ matrix[4] = 0.0f
+ matrix[5] = 1.0f
+ matrix[6] = 0.0f
+ matrix[7] = 0.0f
+ matrix[8] = 0.0f
+ matrix[9] = 0.0f
+ matrix[10] = 1.0f
+ matrix[11] = 0.0f
+ matrix[12] = 0.0f
+ matrix[13] = 0.0f
+ matrix[14] = 0.0f
+ matrix[15] = 1.0f
+ }
+
+ fun mul(other: Matrix4) {
+ mul(other.get())
+ }
+
+ protected fun mul(other: FloatArray) {
+ if (other.size != 16) {
+ throw IllegalArgumentException("Matrix size should be 16!")
+ }
+
+ temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12]
+ temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13]
+ temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14]
+ temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15]
+ temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12]
+ temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13]
+ temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14]
+ temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15]
+ temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12]
+ temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13]
+ temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14]
+ temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15]
+ temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12]
+ temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13]
+ temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14]
+ temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15]
+
+ matrix[0] = temp[0]
+ matrix[1] = temp[1]
+ matrix[2] = temp[2]
+ matrix[3] = temp[3]
+ matrix[4] = temp[4]
+ matrix[5] = temp[5]
+ matrix[6] = temp[6]
+ matrix[7] = temp[7]
+ matrix[8] = temp[8]
+ matrix[9] = temp[9]
+ matrix[10] = temp[10]
+ matrix[11] = temp[11]
+ matrix[12] = temp[12]
+ matrix[13] = temp[13]
+ matrix[14] = temp[14]
+ matrix[15] = temp[15]
+ }
+
+ fun translate(x: Float, y: Float, z: Float) {
+ translateMatrix[12] = x
+ translateMatrix[13] = y
+ translateMatrix[14] = z
+
+ mul(translateMatrix)
+ }
+
+ fun scale(x: Float, y: Float, z: Float) {
+ scaleMatrix[0] = x
+ scaleMatrix[5] = y
+ scaleMatrix[10] = z
+
+ mul(scaleMatrix)
+ }
+
+ fun rotateX(angle: Float) {
+ rotateXMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+ rotateXMatrix[6] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateXMatrix[9] = Math.sin(angle.toDouble()).toFloat()
+ rotateXMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateXMatrix)
+ }
+
+ fun rotateY(angle: Float) {
+ rotateYMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateYMatrix[2] = Math.sin(angle.toDouble()).toFloat()
+ rotateYMatrix[8] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateYMatrix[10] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateYMatrix)
+ }
+
+ fun rotateZ(angle: Float) {
+ rotateZMatrix[0] = Math.cos(angle.toDouble()).toFloat()
+ rotateZMatrix[1] = Math.sin(angle.toDouble()).toFloat()
+ rotateZMatrix[4] = (-Math.sin(angle.toDouble())).toFloat()
+ rotateZMatrix[5] = Math.cos(angle.toDouble()).toFloat()
+
+ mul(rotateZMatrix)
+ }
+}
diff --git a/src/com/persesgames/net/NetUtils.kt b/src/com/persesgames/net/NetUtils.kt
new file mode 100644
index 0000000..b59cbb3
--- /dev/null
+++ b/src/com/persesgames/net/NetUtils.kt
@@ -0,0 +1,18 @@
+package com.persesgames.net
+
+import org.w3c.xhr.XMLHttpRequest
+
+/**
+ * User: rnentjes
+ * Date: 30-7-16
+ * Time: 16:39
+ */
+
+fun getUrlAsString(url: String): String {
+ val req = XMLHttpRequest()
+
+ req.open("GET", url, false)
+ req.send(null)
+
+ return req.responseText
+}
diff --git a/src/com/persesgames/shader/ShaderProgram.kt b/src/com/persesgames/shader/ShaderProgram.kt
new file mode 100644
index 0000000..3c3aad5
--- /dev/null
+++ b/src/com/persesgames/shader/ShaderProgram.kt
@@ -0,0 +1,110 @@
+package com.persesgames.shader
+
+import org.khronos.webgl.*
+
+/**
+ * User: rnentjes
+ * Date: 17-4-16
+ * Time: 15:15
+ */
+
+class ShaderProgram(
+ val webgl: WebGLRenderingContext,
+ val drawType: Int,
+ vertexShaderSource: String,
+ fragmentShaderSource: String,
+ val vainfo: Array,
+ val setter: (program: ShaderProgram, data: T) -> Unit) {
+
+ var shaderProgram: WebGLProgram
+ var vertex: WebGLShader
+ var fragment: WebGLShader
+
+ var verticesBlockSize = 0
+ var drawLength = 0
+
+ init {
+ vertex = compileShader(vertexShaderSource, WebGLRenderingContext.VERTEX_SHADER)
+ fragment = compileShader(fragmentShaderSource, WebGLRenderingContext.FRAGMENT_SHADER)
+
+ shaderProgram = webgl.createProgram() ?: throw IllegalStateException("Unable to request shader program from webgl context!")
+ webgl.attachShader(shaderProgram, vertex)
+ webgl.attachShader(shaderProgram, fragment)
+ webgl.linkProgram(shaderProgram)
+
+ if (webgl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) == false) {
+ println(webgl.getProgramInfoLog(shaderProgram))
+ throw IllegalStateException("Unable to compile shader program!")
+ }
+
+ webgl.useProgram(shaderProgram)
+
+ this.verticesBlockSize = 0;
+
+ // set attribute locations...
+ for (info in vainfo.iterator()) {
+ info.location = webgl.getAttribLocation(shaderProgram, info.locationName)
+ info.offset = verticesBlockSize;
+
+ verticesBlockSize += info.numElements;
+ println("attrib: ${info.locationName}, info.location: ${info.location}, info.offset: ${info.offset}");
+ }
+
+ when(drawType) {
+ WebGLRenderingContext.TRIANGLES -> {
+ drawLength = verticesBlockSize * 3
+ }
+ else -> {
+ drawLength = verticesBlockSize
+ }
+ }
+
+ println("verticesBlockSize $verticesBlockSize");
+
+ println("ShaderProgram constructor done");
+ }
+
+ private fun compileShader(source: String, type: Int): WebGLShader {
+ val result: WebGLShader
+
+ result = webgl.createShader(type) ?: throw IllegalStateException("Unable to request shader from webgl context!")
+ webgl.shaderSource(result, source)
+ webgl.compileShader(result)
+
+ if (webgl.getShaderParameter(result, WebGLRenderingContext.COMPILE_STATUS) == false) {
+ throw IllegalStateException("Unable to compile shader!\n${source}\n\n${webgl.getShaderInfoLog(result)}")
+ }
+
+ return result
+ }
+
+ fun begin(attribBuffer: WebGLBuffer, userdata: T) {
+ webgl.useProgram(shaderProgram);
+ webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer);
+
+ // set attribute locations...
+ for (info in vainfo.iterator()) {
+ webgl.enableVertexAttribArray(info.location)
+ webgl.vertexAttribPointer(info.location, info.numElements, WebGLRenderingContext.FLOAT, false, verticesBlockSize * 4, info.offset * 4)
+ }
+
+ setter(this, userdata)
+ }
+
+ fun end() {
+ for (info in vainfo.iterator()) {
+ webgl.disableVertexAttribArray(info.location);
+ }
+ webgl.useProgram(null)
+ }
+
+ fun getAttribLocation(location: String) = webgl.getAttribLocation(shaderProgram, location);
+
+ fun getUniformLocation(location: String) = webgl.getUniformLocation(shaderProgram, location);
+
+ fun setUniform1f(location: String, value: Float) { webgl.uniform1f(getUniformLocation(location), value); }
+ fun setUniform4f(location: String, v1: Float, v2: Float, v3: Float, v4: Float) { webgl.uniform4f(getUniformLocation(location), v1, v2, v3, v4); }
+ fun setUniform1i(location: String, value: Int) { webgl.uniform1i(getUniformLocation(location), value); }
+ fun setUniformMatrix4fv(location: String, value: Float32Array) { webgl.uniformMatrix4fv(getUniformLocation(location), false, value); }
+
+}
diff --git a/src/com/persesgames/shader/ShaderProgramMesh.kt b/src/com/persesgames/shader/ShaderProgramMesh.kt
new file mode 100644
index 0000000..f4c4dd5
--- /dev/null
+++ b/src/com/persesgames/shader/ShaderProgramMesh.kt
@@ -0,0 +1,71 @@
+package com.persesgames.shader
+
+import org.khronos.webgl.Float32Array
+import org.khronos.webgl.WebGLBuffer
+import org.khronos.webgl.WebGLRenderingContext
+
+/**
+ * User: rnentjes
+ * Date: 14-5-16
+ * Time: 11:57
+ */
+
+class VertextAttributeInfo(val locationName: String, val numElements: Int) {
+ var location = 0
+ var offset = 0
+}
+
+class ShaderProgramMesh(
+ val shaderProgram: ShaderProgram
+) {
+ val webgl = shaderProgram.webgl
+ val data: Float32Array
+ var currentIndex: Int = 0
+ val attribBuffer: WebGLBuffer
+ var counter = 0
+
+ init {
+ data = Float32Array(20000 - (20000 % shaderProgram.drawLength))
+
+ attribBuffer = webgl.createBuffer() ?: throw IllegalStateException("Unable to create webgl buffer!")
+ webgl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, attribBuffer);
+ }
+
+ fun queue(vararg vertices: Float) {
+ queue(vertices as Array)
+ }
+
+ fun queue(vertices: Array) {
+ data.set(vertices, currentIndex)
+ currentIndex += vertices.size
+
+ if (currentIndex == data.length) {
+ println("Skipped draw call, to many values!")
+ currentIndex = 0
+ }
+ }
+
+ fun remaining() = data.length - currentIndex
+
+ fun bufferFull() = currentIndex == data.length
+
+ fun render(userdata: T) {
+ counter++
+ if (currentIndex > 0) {
+/* if (counter % 100 == 0) {
+ println("currentIndex=$currentIndex blockSize=${shaderProgram.verticesBlockSize} drawLength=${shaderProgram.drawLength} drawing=${(currentIndex / shaderProgram.verticesBlockSize).toInt()}")
+ }*/
+ if (currentIndex % shaderProgram.verticesBlockSize != 0) {
+ throw IllegalStateException("Number of vertices not a multiple of the attribute block size!")
+ }
+
+ shaderProgram.begin(attribBuffer, userdata)
+
+ webgl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, data, WebGLRenderingContext.DYNAMIC_DRAW)
+ webgl.drawArrays(shaderProgram.drawType, 0, (currentIndex / shaderProgram.verticesBlockSize).toInt())
+ currentIndex = 0
+
+ shaderProgram.end()
+ }
+ }
+}
diff --git a/src/com/persesgames/shooter/Shooter.kt b/src/com/persesgames/shooter/Shooter.kt
deleted file mode 100644
index 864a1b6..0000000
--- a/src/com/persesgames/shooter/Shooter.kt
+++ /dev/null
@@ -1,206 +0,0 @@
-package com.persesgames.shooter
-
-import com.persesgames.game.DrawMode
-import com.persesgames.game.Game
-import com.persesgames.game.Screen
-import com.persesgames.input.EmptyInputProcessor
-import com.persesgames.input.KeyCode
-import com.persesgames.input.Keys
-import com.persesgames.map.tiled.TiledMap
-import com.persesgames.sound.Music
-import com.persesgames.sound.Sounds
-import com.persesgames.sprite.Sprite
-import com.persesgames.sprite.SpriteBatch
-import com.persesgames.text.Texts
-import com.persesgames.texture.Textures
-import org.w3c.dom.HTMLAudioElement
-import org.w3c.dom.HTMLInputElement
-import kotlin.browser.document
-
-/**
- * Created by rnentjes on 19-4-16.
- */
-
-class GameInputProcessor : EmptyInputProcessor() {
-
- override fun keyPressed(charCode: Int) {
- println("charCode: $charCode")
- if (charCode == 32) {
- Sounds.play("EXPLOSION", 0.5f)
- } else if (charCode == 'x'.toInt()) {
- Sounds.play("DROP", 0.75f)
- }
- }
-
- override fun pointerClick(pointer: Int, x: Float, y: Float) {
- println("POINTER $pointer -> ($x, $y)")
- }
-}
-
-var music: HTMLAudioElement? = null
-var showFPS: Boolean = true
-
-class WelcomeScreen : Screen() {
-
- override fun loadResources() {
- println("loading resource!")
-
- //music = Music.play("music/DST-TechnoBasic.mp3", 1.0, looping = true)
-
- Textures.loadSpriteSheet("images/data-0.json")
-
- Keys.setInputProcessor(GameInputProcessor())
- }
-
- override fun update(time: Float, delta: Float) { }
-
- override fun render() {
-
- if (showFPS) {
- Texts.drawText(20f, 100f, "Hello! FPS ${Game.fps}", font = "bold 72pt Arial")
- }
- }
-}
-
-class GameScreen : Screen() {
- val map = TiledMap("maps", "level_1_01.json")
-
- var sprites = SpriteBatch()
- var x = 0f
- var y = 15500f
- var sprite = Sprite("SHIP")
- var numberOfSprites: Int = 5000
- var time: Float = 0f
-
- override fun loadResources() {
- Textures.load("SHIP", "images/ship2.png")
-
- Sounds.load("EXPLOSION", "sounds/Explosion7.ogg", channels = 2)
- Sounds.load("DROP", "sounds/Bomb_Drop.ogg", channels = 4)
-
- music = Music.play("music/DST-TechnoBasic.mp3", 0.5, looping = true)
-
- Keys.setInputProcessor(GameInputProcessor())
-
- println("width: ${map.data.width}")
- println("height: ${map.data.height}")
- println("layers: ${map.data.layers?.size}")
-
- val layers = map.data.layers
- if (layers != null) {
- println("layer0: ${layers[0].name}")
- }
- val tilesets = map.data.tilesets
- if (tilesets != null) {
- println("tilesets ${tilesets.size}")
- println("tileset0: ${tilesets[0].name}")
- }
- }
-
- override fun update(time: Float, delta: Float) {
- this.time = time
- val speed = 1500f // units per second
-
- if (Keys.isDown(KeyCode.LEFT)) {
- x -= delta * speed
- println("x=$x")
- }
-
- if (Keys.isDown(KeyCode.RIGHT)) {
- x += delta * speed
- println("x=$x")
- }
-
- if (Keys.isDown(KeyCode.UP)) {
- y += delta * speed
- println("y=$y")
- }
-
- if (Keys.isDown(KeyCode.DOWN)) {
- y -= delta * speed
- println("y=$y")
- }
-
- if (Keys.isDown(KeyCode.MINUS)) {
- if (numberOfSprites > 25) {
- numberOfSprites = (numberOfSprites * 0.9f).toInt()
- }
- }
-
- if (Keys.isDown(KeyCode.PLUS)) {
- numberOfSprites = (numberOfSprites * 1.1f).toInt()
- }
- }
-
- override fun render() {
- var r = 0f
- var d = 0f
- var x = 0f
- var y = 0f
-
- map.drawLayer(1, this.x, this.y)
- map.drawLayer(2, this.x, this.y)
-
- val time = this.time / 10f
- for (index in 0..numberOfSprites) {
- r = index * 0.05f
- d = index * 2.13f
- x = 1000f + (Math.sin((time + d).toDouble()) * r).toFloat()
- y = 500f + (Math.cos((time + d).toDouble()) * r).toFloat()
-
- sprites.draw(sprite, x.toFloat(), y.toFloat(), scale = 0.4f + Math.sin(time.toDouble() + r).toFloat(), rotation = r * 10f)
- }
-
- sprites.draw(sprite, 350f, 350f, scale = 4f, rotation = -time)
-
- sprites.render()
-
- Texts.drawText(20f, 150f, "Drawing $numberOfSprites sprites per frame.")
-
- if (showFPS) {
- Texts.drawText(20f, 100f, "FPS ${Game.fps}", font = "bold 72pt Arial", fillStyle = "red")
- Texts.drawText(15f, -20f, "Music by DST", font = "bold 28pt Arial", fillStyle = "green")
- }
- }
-
-}
-
-fun main(args: Array) {
- Game.view.setToHeight(1000f)
- Game.view.drawMode = DrawMode.LINEAR
-
- Game.view.minAspectRatio = 0.9f
- Game.view.maxAspectRatio = 1.5f
-
- Game.start(WelcomeScreen())
-}
-
-fun changeMusic(it: HTMLInputElement) {
- val mus = music
-
- if (mus != null) {
- if (it.checked) {
- mus.volume = 0.5
- } else {
- mus.volume = 0.0
- }
- }
-}
-
-fun showFPS(it: HTMLInputElement) {
- showFPS = it.checked
-}
-
-fun pause(it: HTMLInputElement) {
- Game.pause = it.checked
-}
-
-fun playGame() {
- document.getElementById("menu")?.setAttribute("style", "display: none;")
-
- Game.setScreen(GameScreen())
-}
-
-fun fullscreen() {
- Game.view.requestFullscreen()
-}
diff --git a/src/com/persesgames/sound/Music.kt b/src/com/persesgames/sound/Music.kt
new file mode 100644
index 0000000..88a531d
--- /dev/null
+++ b/src/com/persesgames/sound/Music.kt
@@ -0,0 +1,49 @@
+package com.persesgames.sound
+
+import org.w3c.dom.HTMLAudioElement
+import java.util.*
+import kotlin.browser.document
+import kotlin.dom.on
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 13:02
+ */
+
+object Music {
+ val playing: MutableSet = HashSet()
+
+ fun load(url: String): HTMLAudioElement {
+ val audio = document.createElement("audio") as HTMLAudioElement
+
+ audio.src = url
+
+ return audio;
+ }
+
+ fun play(url: String, volume: Double = 0.75, looping: Boolean = false): HTMLAudioElement {
+ val audio = document.createElement("audio") as HTMLAudioElement
+
+ audio.src = url
+ audio.volume = volume
+ audio.play()
+
+ audio.on("ended", true, {
+ if (looping) {
+ audio.currentTime = 0.0
+ audio.play()
+ } else {
+ println("REMOVING: $audio")
+ audio.remove()
+ playing.remove(audio)
+ }
+ })
+
+ return audio
+ }
+
+ fun stopAll() {
+
+ }
+}
diff --git a/src/com/persesgames/sound/Sounds.kt b/src/com/persesgames/sound/Sounds.kt
new file mode 100644
index 0000000..8d8c549
--- /dev/null
+++ b/src/com/persesgames/sound/Sounds.kt
@@ -0,0 +1,62 @@
+package com.persesgames.sound
+
+import org.w3c.dom.HTMLAudioElement
+import java.util.*
+import kotlin.browser.document
+
+/**
+ * User: rnentjes
+ * Date: 18-5-16
+ * Time: 12:34
+ */
+
+class Sound(val name:String, val url: String, val volume: Double = 0.75, val numberOfChannels: Int) {
+ var channels: Array
+ var nextChannel: Int = 0
+
+ init {
+ println("CREATING: $name")
+ channels = Array(numberOfChannels, { document.createElement("audio") as HTMLAudioElement })
+
+ for (audio in channels) {
+ audio.src = url
+ audio.pause()
+ audio.load()
+ audio.volume = volume
+ }
+ }
+
+ fun play() {
+ println("PLAYING: $name - $nextChannel")
+ channels[nextChannel].currentTime = 0.0
+ channels[nextChannel].play()
+
+ nextChannel = (nextChannel + 1) % channels.size
+ }
+
+ fun pause() {
+ for (audio in channels) {
+ audio.pause()
+ }
+ }
+}
+
+object Sounds {
+ val sounds: MutableMap = HashMap()
+
+ fun load(name: String, url: String, volume: Double = 0.75, channels: Int = 1 ) {
+ sounds.put(name, Sound(name, url, volume, channels))
+ }
+
+ fun play(name: String, volume: Float = 0.75f) {
+ val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!")
+
+ sound.play()
+ }
+
+ fun pause(name: String) {
+ val sound: Sound = sounds[name] ?: throw IllegalArgumentException("Sound '$name' not found, load it first!")
+
+ sound.pause()
+ }
+}
diff --git a/src/com/persesgames/sprite/SpriteBatch.kt b/src/com/persesgames/sprite/SpriteBatch.kt
new file mode 100644
index 0000000..8f72f31
--- /dev/null
+++ b/src/com/persesgames/sprite/SpriteBatch.kt
@@ -0,0 +1,26 @@
+package com.persesgames.sprite
+
+import com.persesgames.texture.Texture
+import com.persesgames.texture.Textures
+
+/**
+ * User: rnentjes
+ * Date: 20-4-16
+ * Time: 13:48
+ */
+
+class Sprite(val textureName: String) {
+ val texture: Texture by lazy { Textures.get(textureName) }
+}
+
+class SpriteBatch {
+
+ fun draw(sprite: Sprite, x: Float, y: Float, scale: Float = 1f, rotation: Float = 0f) {
+ sprite.texture.queueDraw(x, y, scale, rotation)
+ }
+
+ fun render() {
+ Textures.render()
+ }
+
+}
diff --git a/src/com/persesgames/text/Texts.kt b/src/com/persesgames/text/Texts.kt
new file mode 100644
index 0000000..b0e2a17
--- /dev/null
+++ b/src/com/persesgames/text/Texts.kt
@@ -0,0 +1,30 @@
+package com.persesgames.text
+
+import com.persesgames.game.Game
+
+/**
+ * Created by rnentjes on 16-5-16.
+ */
+
+object Texts {
+
+ fun drawText(x: Float, y: Float, message: String, font: String = "bold 24pt Arial", fillStyle: String = "white") {
+ var yy = y
+ if (yy < 0) {
+ yy += Game.view.height
+ }
+ Game.html.canvas2d.fillStyle = fillStyle
+ Game.html.canvas2d.font = font
+ Game.html.canvas2d.fillText(message, x.toDouble(), yy.toDouble())
+ }
+
+ fun drawLeftTop(left: Float, top: Float, message: String, font: String = "bold 24pt Arial", fillStyle: String = "white") {
+ drawText(
+ Game.view.gameToScreenCoordX(-Game.view.width / 2f + left),
+ Game.view.gameToScreenCoordY(Game.view.height / 2f - top),
+ message,
+ font,
+ fillStyle
+ )
+ }
+}
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ac7e0ef..ab5a486 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,6 +4,8 @@
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
deleted file mode 100644
index 5ab55b9..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_3.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
deleted file mode 100644
index 1ad4a3f..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
new file mode 100644
index 0000000..c38b651
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_js_library_1_1_0_beta_18.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
deleted file mode 100644
index 6958289..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
deleted file mode 100644
index b2af125..0000000
--- a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_5_2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 4051f93..81ed488 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,9 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test.iml b/.idea/modules/kotlin-webgl-test.iml
deleted file mode 100644
index 3bc84ee..0000000
--- a/.idea/modules/kotlin-webgl-test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules/kotlin-webgl-test_main.iml b/.idea/modules/kotlin-webgl-test_main.iml
deleted file mode 100644
index 61e01d4..0000000
--- a/.idea/modules/kotlin-webgl-test_main.iml
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-