diff --git a/.build b/.build
new file mode 100644
index 0000000..62f9457
--- /dev/null
+++ b/.build
@@ -0,0 +1 @@
+6
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1172fa4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+bin
+unoptimized assets
+/*.keystore
diff --git a/Raider Wings.hxproj b/Raider Wings.hxproj
new file mode 100644
index 0000000..b2df5b3
--- /dev/null
+++ b/Raider Wings.hxproj
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application.xml b/application.xml
new file mode 100644
index 0000000..9f26ed3
--- /dev/null
+++ b/application.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/effects/bulletHit/bulletHit.png b/assets/effects/bulletHit/bulletHit.png
new file mode 100644
index 0000000..b3aa363
Binary files /dev/null and b/assets/effects/bulletHit/bulletHit.png differ
diff --git a/assets/effects/debries/debries1.png b/assets/effects/debries/debries1.png
new file mode 100644
index 0000000..5d22949
Binary files /dev/null and b/assets/effects/debries/debries1.png differ
diff --git a/assets/effects/debries/debries2.png b/assets/effects/debries/debries2.png
new file mode 100644
index 0000000..a4ccfe9
Binary files /dev/null and b/assets/effects/debries/debries2.png differ
diff --git a/assets/effects/debries/debries3.png b/assets/effects/debries/debries3.png
new file mode 100644
index 0000000..15f2915
Binary files /dev/null and b/assets/effects/debries/debries3.png differ
diff --git a/assets/effects/explosion1/1.png b/assets/effects/explosion1/1.png
new file mode 100644
index 0000000..9be0ef5
Binary files /dev/null and b/assets/effects/explosion1/1.png differ
diff --git a/assets/effects/explosion1/2.png b/assets/effects/explosion1/2.png
new file mode 100644
index 0000000..5117873
Binary files /dev/null and b/assets/effects/explosion1/2.png differ
diff --git a/assets/effects/explosion1/3.png b/assets/effects/explosion1/3.png
new file mode 100644
index 0000000..40e9850
Binary files /dev/null and b/assets/effects/explosion1/3.png differ
diff --git a/assets/effects/explosion1/4.png b/assets/effects/explosion1/4.png
new file mode 100644
index 0000000..a6219aa
Binary files /dev/null and b/assets/effects/explosion1/4.png differ
diff --git a/assets/effects/explosion1/5.png b/assets/effects/explosion1/5.png
new file mode 100644
index 0000000..9b64e9c
Binary files /dev/null and b/assets/effects/explosion1/5.png differ
diff --git a/assets/effects/projectiles/beam01.png b/assets/effects/projectiles/beam01.png
new file mode 100644
index 0000000..076e305
Binary files /dev/null and b/assets/effects/projectiles/beam01.png differ
diff --git a/assets/effects/projectiles/beam02.png b/assets/effects/projectiles/beam02.png
new file mode 100644
index 0000000..7342da0
Binary files /dev/null and b/assets/effects/projectiles/beam02.png differ
diff --git a/assets/effects/projectiles/enemyBalloonBullet.png b/assets/effects/projectiles/enemyBalloonBullet.png
new file mode 100644
index 0000000..0535337
Binary files /dev/null and b/assets/effects/projectiles/enemyBalloonBullet.png differ
diff --git a/assets/effects/projectiles/railgunTrail.png b/assets/effects/projectiles/railgunTrail.png
new file mode 100644
index 0000000..fe75a3b
Binary files /dev/null and b/assets/effects/projectiles/railgunTrail.png differ
diff --git a/assets/effects/smoke/smoke01.png b/assets/effects/smoke/smoke01.png
new file mode 100644
index 0000000..27f7771
Binary files /dev/null and b/assets/effects/smoke/smoke01.png differ
diff --git a/assets/effects/smoke/smoke02.png b/assets/effects/smoke/smoke02.png
new file mode 100644
index 0000000..1d8db49
Binary files /dev/null and b/assets/effects/smoke/smoke02.png differ
diff --git a/assets/effects/smoke/smoke03.png b/assets/effects/smoke/smoke03.png
new file mode 100644
index 0000000..1909520
Binary files /dev/null and b/assets/effects/smoke/smoke03.png differ
diff --git a/assets/effects/smoke/smoke04.png b/assets/effects/smoke/smoke04.png
new file mode 100644
index 0000000..10ac4e4
Binary files /dev/null and b/assets/effects/smoke/smoke04.png differ
diff --git a/assets/effects/smoke/smoke05.png b/assets/effects/smoke/smoke05.png
new file mode 100644
index 0000000..4632cc2
Binary files /dev/null and b/assets/effects/smoke/smoke05.png differ
diff --git a/assets/fonts/04B_03.TTF b/assets/fonts/04B_03.TTF
new file mode 100644
index 0000000..fe4328b
Binary files /dev/null and b/assets/fonts/04B_03.TTF differ
diff --git a/assets/fonts/04B_03.TTF.hash b/assets/fonts/04B_03.TTF.hash
new file mode 100644
index 0000000..d87af26
--- /dev/null
+++ b/assets/fonts/04B_03.TTF.hash
@@ -0,0 +1 @@
+oy4:hashq:111oy6:ascentd768y4:dataad384d894.976d384d641.024d128d641.024d128d894.976d384d894.976d128d896d0d896d0d640d128d640d128d512d384d512d384d640d512d640d512d896d384d896d384d1024d128d1024d128d896hy6:_widthd640y4:xMaxd512y4:xMind0y4:yMaxd512y4:yMind0y7:_heightd512y7:leadingd0y7:descentd256y8:charCodei111y15:leftsideBearingd0y12:advanceWidthd640y8:commandsai1i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2i2i2hg:223oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i223R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:110oR1d768R2ad384d1024d512d1024d512d640d384d640d384d1024d128d640d384d640d384d512d0d512d0d1024d128d1024d128d640hR3d640R4d512R5d0R6d512R7d0R8d512R9d0R10d256R11i110R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i2i2hg:222oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i222R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:109oR1d768R2ad0d512d0d1024d128d1024d128d640d256d640d256d1024d384d1024d384d640d512d640d512d512d0d512d512d1024d640d1024d640d640d512d640d512d1024hR3d768R4d640R5d0R6d512R7d0R8d512R9d0R10d256R11i109R12d0R13d768R14ai1i2i2i2i2i2i2i2i2i2i2i1i2i2i2i2hg:221oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i221R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:108oR1d768R2ad128d384d0d384d0d1024d128d1024d128d384hR3d256R4d128R5d0R6d640R7d0R8d640R9d0R10d256R11i108R12d0R13d256R14ai1i2i2i2i2hg:220oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i220R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:107oR1d768R2ad384d640d256d640d256d768d128d768d128d384d0d384d0d1024d128d1024d128d896d384d896d384d640d512d512d384d512d384d640d512d640d512d512d512d1024d512d896d384d896d384d1024d512d1024hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i107R12d0R13d640R14ai1i2i2i2i2i2i2i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:219oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i219R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:106oR1d768R2ad256d384d128d384d128d512d256d512d256d384d256d640d128d640d128d1152d256d1152d256d640d128d1152d0d1152d0d1280d128d1280d128d1152hR3d384R4d256R5d0R6d640R7d-256R8d640R9d0R10d256R11i106R12d0R13d384R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:218oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i218R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:105oR1d768R2ad128d384d0d384d0d512d128d512d128d384d128d640d0d640d0d1024d128d1024d128d640hR3d256R4d128R5d0R6d640R7d0R8d640R9d0R10d256R11i105R12d0R13d256R14ai1i2i2i2i2i1i2i2i2i2hg:217oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i217R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:104oR1d768R2ad128d512d128d384d0d384d0d1024d128d1024d128d640d384d640d384d512d128d512d384d1024d512d1024d512d640d384d640d384d1024hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i104R12d0R13d640R14ai1i2i2i2i2i2i2i2i2i1i2i2i2i2hg:216oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i216R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:103oR1d768R2ad128d894.976d384d894.976d384d641.024d128d641.024d128d894.976d128d1152d384d1152d384d1024d128d1024d128d896d0d896d0d640d128d640d128d512d512d512d512d1152d384d1152d384d1280d128d1280d128d1152hR3d640R4d512R5d0R6d512R7d-256R8d512R9d0R10d256R11i103R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2i2i2i2i2hg:215oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i215R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:102oR1d768R2ad384d384d256d384d256d512d384d512d384d384d128d512d128d640d0d640d0d768d128d768d128d1024d256d1024d256d768d384d768d384d640d256d640d256d512d128d512hR3d512R4d384R5d0R6d640R7d0R8d640R9d0R10d256R11i102R12d0R13d512R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2i2i2hg:214oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i214R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:101oR1d768R2ad256d766.976d256d641.024d128d641.024d128d766.976d256d766.976d128d1024d128d896d0d896d0d640d128d640d128d512d384d512d384d640d512d640d512d768d256d768d256d896d384d896d384d1024d128d1024hR3d640R4d512R5d0R6d512R7d0R8d512R9d0R10d256R11i101R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2i2i2i2i2hg:213oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i213R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:100oR1d768R2ad128d894.976d384d894.976d384d641.024d128d641.024d128d894.976d128d640d128d512d384d512d384d384d512d384d512d1024d128d1024d128d896d0d896d0d640d128d640hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i100R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2hg:212oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i212R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:99oR1d768R2ad384d640d384d512d128d512d128d640d384d640d128d640d0d640d0d896d128d896d128d640d384d1024d384d896d128d896d128d1024d384d1024hR3d512R4d384R5d0R6d512R7d0R8d512R9d0R10d256R11i99R12d0R13d512R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:211oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i211R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:98oR1d768R2ad384d640d512d640d512d896d384d896d384d1024d0d1024d0d384d128d384d128d512d384d512d384d640d128d894.976d384d894.976d384d641.024d128d641.024d128d894.976hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i98R12d0R13d640R14ai1i2i2i2i2i2i2i2i2i2i2i1i2i2i2i2hg:210oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i210R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:97oR1d768R2ad128d894.976d384d894.976d384d641.024d128d641.024d128d894.976d128d640d128d512d512d512d512d1024d128d1024d128d896d0d896d0d640d128d640hR3d640R4d512R5d0R6d512R7d0R8d512R9d0R10d256R11i97R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2hg:209oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i209R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:96oR1d768R2ad0d384d0d512d128d512d128d384d0d384d128d640d256d640d256d512d128d512d128d640hR3d384R4d256R5d0R6d640R7d384R8d640R9d0R10d256R11i96R12d0R13d384R14ai1i2i2i2i2i1i2i2i2i2hg:208oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i208R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:95oR1d768R2ad0d896d0d1024d512d1024d512d896d0d896hR3d640R4d512R5d0R6d128R7d0R8d128R9d0R10d256R11i95R12d0R13d640R14ai1i2i2i2i2hg:207oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i207R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:94oR1d768R2ad128d384d128d512d256d512d256d384d128d384d0d640d128d640d128d512d0d512d0d640d256d640d384d640d384d512d256d512d256d640hR3d512R4d384R5d0R6d640R7d384R8d640R9d0R10d256R11i94R12d0R13d512R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:206oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i206R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:93oR1d768R2ad256d1024d256d384d0d384d0d512d128d512d128d896d0d896d0d1024d256d1024hR3d384R4d256R5d0R6d640R7d0R8d640R9d0R10d256R11i93R12d0R13d384R14ai1i2i2i2i2i2i2i2i2hg:205oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i205R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:92oR1d768R2ad256d640d128d640d128d512d256d512d256d640d128d384d128d512d0d512d0d384d128d384d512d896d384d896d384d768d512d768d512d896d384d768d256d768d256d640d384d640d384d768d640d1024d512d1024d512d896d640d896d640d1024hR3d768R4d640R5d0R6d640R7d0R8d640R9d0R10d256R11i92R12d0R13d768R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:204oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i204R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:91oR1d768R2ad0d384d0d1024d256d1024d256d896d128d896d128d512d256d512d256d384d0d384hR3d384R4d256R5d0R6d640R7d0R8d640R9d0R10d256R11i91R12d0R13d384R14ai1i2i2i2i2i2i2i2i2hg:203oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i203R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:90oR1d768R2ad384d384d0d384d0d512d256d512d256d640d384d640d384d384d256d640d128d640d128d768d256d768d256d640d384d1024d384d896d128d896d128d768d0d768d0d1024d384d1024hR3d512R4d384R5d0R6d640R7d0R8d640R9d0R10d256R11i90R12d0R13d512R14ai1i2i2i2i2i2i2i1i2i2i2i2i1i2i2i2i2i2i2hg:202oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i202R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:89oR1d768R2ad128d384d0d384d0d640d128d640d128d384d384d640d128d640d128d768d384d768d384d896d512d896d512d384d384d384d384d640d128d896d128d1024d384d1024d384d896d128d896hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i89R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2i1i2i2i2i2hg:201oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i201R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:88oR1d768R2ad128d384d0d384d0d640d128d640d128d384d512d384d384d384d384d640d512d640d512d384d384d768d384d640d128d640d128d768d384d768d128d768d0d768d0d1024d128d1024d128d768d384d1024d512d1024d512d768d384d768d384d1024hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i88R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:200oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i200R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:87oR1d768R2ad128d384d0d384d0d896d128d896d128d384d384d512d256d512d256d896d384d896d384d512d128d1024d256d1024d256d896d128d896d128d1024d384d1024d512d1024d512d896d384d896d384d1024d512d384d512d896d640d896d640d384d512d384hR3d768R4d640R5d0R6d640R7d0R8d640R9d0R10d256R11i87R12d0R13d768R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:199oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i199R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:86oR1d768R2ad0d896d128d896d128d384d0d384d0d896d256d896d384d896d384d640d256d640d256d896d384d384d384d640d512d640d512d384d384d384d128d1024d256d1024d256d896d128d896d128d1024hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i86R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:198oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i198R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:85oR1d768R2ad384d896d512d896d512d384d384d384d384d896d128d384d0d384d0d896d128d896d128d384d128d896d128d1024d384d1024d384d896d128d896hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i85R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:197oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i197R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:84oR1d768R2ad128d1024d256d1024d256d512d384d512d384d384d0d384d0d512d128d512d128d1024hR3d512R4d384R5d0R6d640R7d0R8d640R9d0R10d256R11i84R12d0R13d512R14ai1i2i2i2i2i2i2i2i2hg:196oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i196R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:83oR1d768R2ad0d640d128d640d128d512d0d512d0d640d128d384d128d512d512d512d512d384d128d384d384d768d384d640d128d640d128d768d384d768d512d896d512d768d384d768d384d896d512d896d0d896d0d1024d384d1024d384d896d0d896hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i83R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:195oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i195R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:82oR1d768R2ad512d1024d384d1024d384d896d128d896d128d1024d0d1024d0d384d384d384d384d510.976d128d510.976d128d766.976d384d766.976d384d512d512d512d512d768d384d768d384d896d512d896d512d1024hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i82R12d0R13d640R14ai1i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2hg:194oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i194R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:81oR1d768R2ad384d894.976d384d513.024d128d513.024d128d894.976d384d894.976d128d896d0d896d0d512d128d512d128d384d384d384d384d512d512d512d512d896d384d896d384d1024d512d1024d512d1152d384d1152d384d1024d128d1024d128d896hR3d640R4d512R5d0R6d640R7d-128R8d640R9d0R10d256R11i81R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2hg:193oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i193R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:80oR1d768R2ad384d512d512d512d512d768d384d768d384d896d128d896d128d1024d0d1024d0d384d384d384d384d512d128d766.976d384d766.976d384d513.024d128d513.024d128d766.976hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i80R12d0R13d640R14ai1i2i2i2i2i2i2i2i2i2i2i1i2i2i2i2hg:192oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i192R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:79oR1d768R2ad384d894.976d384d513.024d128d513.024d128d894.976d384d894.976d128d896d0d896d0d512d128d512d128d384d384d384d384d512d512d512d512d896d384d896d384d1024d128d1024d128d896hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i79R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2i2i2hg:191oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i191R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:78oR1d768R2ad384d768d384d1024d512d1024d512d384d384d384d384d640d256d640d256d768d384d768d128d640d256d640d256d512d128d512d128d384d0d384d0d1024d128d1024d128d640hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i78R12d0R13d640R14ai1i2i2i2i2i2i2i2i2i1i2i2i2i2i2i2i2i2hg:190oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i190R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:77oR1d768R2ad128d512d128d384d0d384d0d1024d128d1024d128d640d256d640d256d512d128d512d256d768d384d768d384d640d256d640d256d768d512d512d384d512d384d640d512d640d512d1024d640d1024d640d384d512d384d512d512hR3d768R4d640R5d0R6d640R7d0R8d640R9d0R10d256R11i77R12d0R13d768R14ai1i2i2i2i2i2i2i2i2i1i2i2i2i2i1i2i2i2i2i2i2i2i2hg:189oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i189R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:76oR1d768R2ad384d1024d384d896d128d896d128d384d0d384d0d1024d384d1024hR3d512R4d384R5d0R6d640R7d0R8d640R9d0R10d256R11i76R12d0R13d512R14ai1i2i2i2i2i2i2hg:188oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i188R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:75oR1d768R2ad128d384d0d384d0d1024d128d1024d128d768d256d768d256d640d128d640d128d384d384d512d512d512d512d384d384d384d384d512d256d640d384d640d384d512d256d512d256d640d384d896d384d768d256d768d256d896d384d896d512d1024d512d896d384d896d384d1024d512d1024hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i75R12d0R13d640R14ai1i2i2i2i2i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:187oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i187R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:74oR1d768R2ad256d384d256d512d384d512d384d896d512d896d512d384d256d384d0d768d0d896d128d896d128d768d0d768d128d896d128d1024d384d1024d384d896d128d896hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i74R12d0R13d640R14ai1i2i2i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:186oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i186R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:73oR1d768R2ad256d512d384d512d384d384d0d384d0d512d128d512d128d896d0d896d0d1024d384d1024d384d896d256d896d256d512hR3d512R4d384R5d0R6d640R7d0R8d640R9d0R10d256R11i73R12d0R13d512R14ai1i2i2i2i2i2i2i2i2i2i2i2i2hg:185oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i185R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:72oR1d768R2ad384d640d128d640d128d384d0d384d0d1024d128d1024d128d768d384d768d384d1024d512d1024d512d384d384d384d384d640hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i72R12d0R13d640R14ai1i2i2i2i2i2i2i2i2i2i2i2i2hg:184oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i184R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:71oR1d768R2ad512d512d512d384d128d384d128d512d512d512d128d512d0d512d0d896d128d896d128d512d512d1024d128d1024d128d896d384d896d384d768d256d768d256d640d512d640d512d1024hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i71R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i2i2i2i2hg:183oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i183R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:70oR1d768R2ad128d768d384d768d384d640d128d640d128d512d384d512d384d384d0d384d0d1024d128d1024d128d768hR3d512R4d384R5d0R6d640R7d0R8d640R9d0R10d256R11i70R12d0R13d512R14ai1i2i2i2i2i2i2i2i2i2i2hg:182oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i182R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:69oR1d768R2ad384d1024d384d896d128d896d128d768d384d768d384d640d128d640d128d512d384d512d384d384d0d384d0d1024d384d1024hR3d512R4d384R5d0R6d640R7d0R8d640R9d0R10d256R11i69R12d0R13d512R14ai1i2i2i2i2i2i2i2i2i2i2i2i2hg:181oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i181R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:68oR1d768R2ad384d894.976d384d513.024d128d513.024d128d894.976d384d894.976d384d1024d0d1024d0d384d384d384d384d512d512d512d512d896d384d896d384d1024hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i68R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2hg:180oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i180R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:67oR1d768R2ad384d512d384d384d128d384d128d512d384d512d128d512d0d512d0d896d128d896d128d512d384d1024d384d896d128d896d128d1024d384d1024hR3d512R4d384R5d0R6d640R7d0R8d640R9d0R10d256R11i67R12d0R13d512R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:179oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i179R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:66oR1d768R2ad128d638.976d384d638.976d384d513.024d128d513.024d128d638.976d384d769.024d128d769.024d128d894.976d384d894.976d384d769.024d512d896d384d896d384d1024d0d1024d0d384d384d384d384d512d512d512d512d640d384d640d384d768d512d768d512d896hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i66R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2i2i2hg:178oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i178R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:65oR1d768R2ad128d512d128d384d384d384d384d512d512d512d512d1024d384d1024d384d896d128d896d128d1024d0d1024d0d512d128d512d384d768d384d513.024d128d513.024d128d768d384d768hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i65R12d0R13d640R14ai1i2i2i2i2i2i2i2i2i2i2i2i2i1i2i2i2i2hg:177oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i177R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:64oR1d768R2ad512d894.976d512d768d384d768d384d894.976d512d894.976d512d513.024d128d513.024d128d894.976d256d894.976d256d640d512d640d512d513.024d640d512d640d896d512d896d512d1024d128d1024d128d896d0d896d0d512d128d512d128d384d512d384d512d512d640d512hR3d768R4d640R5d0R6d640R7d0R8d640R9d0R10d256R11i64R12d0R13d768R14ai1i2i2i2i2i1i2i2i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2i2i2hg:176oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i176R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:63oR1d768R2ad0d384d0d512d384d512d384d384d0d384d384d640d512d640d512d512d384d512d384d640d128d640d128d768d384d768d384d640d128d640d128d1024d256d1024d256d896d128d896d128d1024hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i63R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:175oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i175R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:62oR1d768R2ad0d384d0d512d128d512d128d384d0d384d128d512d128d640d256d640d256d512d128d512d128d896d256d896d256d768d128d768d128d896d256d768d384d768d384d640d256d640d256d768d0d1024d128d1024d128d896d0d896d0d1024hR3d512R4d384R5d0R6d640R7d0R8d640R9d0R10d256R11i62R12d0R13d512R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:174oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i174R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:61oR1d768R2ad0d512d0d640d384d640d384d512d0d512d0d768d0d896d384d896d384d768d0d768hR3d512R4d384R5d0R6d512R7d128R8d512R9d0R10d256R11i61R12d0R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:173oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i173R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:60oR1d768R2ad128d640d256d640d256d512d128d512d128d640d256d512d384d512d384d384d256d384d256d512d0d768d128d768d128d640d0d640d0d768d256d896d256d768d128d768d128d896d256d896d384d1024d384d896d256d896d256d1024d384d1024hR3d512R4d384R5d0R6d640R7d0R8d640R9d0R10d256R11i60R12d0R13d512R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:172oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i172R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:59oR1d768R2ad128d512d0d512d0d640d128d640d128d512d128d768d0d768d0d1024d128d1024d128d768hR3d256R4d128R5d0R6d512R7d0R8d512R9d0R10d256R11i59R12d0R13d256R14ai1i2i2i2i2i1i2i2i2i2hg:171oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i171R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:58oR1d768R2ad0d640d128d640d128d512d0d512d0d640d0d896d128d896d128d768d0d768d0d896hR3d256R4d128R5d0R6d512R7d128R8d512R9d0R10d256R11i58R12d0R13d256R14ai1i2i2i2i2i1i2i2i2i2hg:170oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i170R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:57oR1d768R2ad128d513.024d128d638.976d384d638.976d384d513.024d128d513.024d128d896d384d896d384d768d128d768d128d640d0d640d0d512d128d512d128d384d384d384d384d512d512d512d512d896d384d896d384d1024d128d1024d128d896hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i57R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2hg:169oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i169R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:56oR1d768R2ad384d638.976d384d513.024d128d513.024d128d638.976d384d638.976d384d894.976d384d769.024d128d769.024d128d894.976d384d894.976d128d896d0d896d0d768d128d768d128d640d0d640d0d512d128d512d128d384d384d384d384d512d512d512d512d640d384d640d384d768d512d768d512d896d384d896d384d1024d128d1024d128d896hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i56R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2hg:168oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i168R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:55oR1d768R2ad0d384d0d512d384d512d384d640d512d640d512d384d0d384d128d1024d256d1024d256d768d128d768d128d1024d256d768d384d768d384d640d256d640d256d768hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i55R12d0R13d640R14ai1i2i2i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:167oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i167R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:54oR1d768R2ad384d894.976d384d769.024d128d769.024d128d894.976d384d894.976d128d896d0d896d0d512d128d512d128d384d384d384d384d512d128d512d128d640d384d640d384d768d512d768d512d896d384d896d384d1024d128d1024d128d896hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i54R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2hg:166oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i166R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:53oR1d768R2ad128d640d128d512d512d512d512d384d0d384d0d768d384d768d384d640d128d640d512d768d384d768d384d896d512d896d512d768d384d1024d384d896d0d896d0d1024d384d1024hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i53R12d0R13d640R14ai1i2i2i2i2i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:165oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i165R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:52oR1d768R2ad128d641.024d128d768d256d768d256d641.024d128d641.024d384d384d384d768d512d768d512d896d384d896d384d1024d256d1024d256d896d0d896d0d640d128d640d128d512d256d512d256d384d384d384hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i52R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2i2i2i2i2hg:164oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i164R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:51oR1d768R2ad0d384d0d512d384d512d384d384d0d384d384d640d512d640d512d512d384d512d384d640d128d640d128d768d384d768d384d640d128d640d512d896d512d768d384d768d384d896d512d896d0d896d0d1024d384d1024d384d896d0d896hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i51R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:163oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i163R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:50oR1d768R2ad0d384d0d512d384d512d384d384d0d384d384d640d512d640d512d512d384d512d384d640d128d640d128d768d384d768d384d640d128d640d0d1024d512d1024d512d896d128d896d128d768d0d768d0d1024hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i50R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i2i2hg:162oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i162R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:49oR1d768R2ad128d1024d256d1024d256d384d0d384d0d512d128d512d128d1024hR3d384R4d256R5d0R6d640R7d0R8d640R9d0R10d256R11i49R12d0R13d384R14ai1i2i2i2i2i2i2hg:161oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i161R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:48oR1d768R2ad384d894.976d384d513.024d128d513.024d128d894.976d384d894.976d128d896d0d896d0d512d128d512d128d384d384d384d384d512d512d512d512d896d384d896d384d1024d128d1024d128d896hR3d640R4d512R5d0R6d640R7d0R8d640R9d0R10d256R11i48R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2i2i2hg:160oR1d768R2ahR3d512R4d0R5d0R6d0R7d0R8d0R9d0R10d256R11i160R12d0R13d512R14ahg:47oR1d768R2ad384d640d512d640d512d512d384d512d384d640d512d384d512d512d640d512d640d384d512d384d128d896d256d896d256d768d128d768d128d896d256d768d384d768d384d640d256d640d256d768d0d1024d128d1024d128d896d0d896d0d1024hR3d768R4d640R5d0R6d640R7d0R8d640R9d0R10d256R11i47R12d0R13d768R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:159oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i159R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:46oR1d768R2ad0d1024d128d1024d128d896d0d896d0d1024hR3d256R4d128R5d0R6d128R7d0R8d128R9d0R10d256R11i46R12d0R13d256R14ai1i2i2i2i2hg:158oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i158R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:45oR1d768R2ad0d640d0d768d384d768d384d640d0d640hR3d512R4d384R5d0R6d384R7d256R8d384R9d0R10d256R11i45R12d0R13d512R14ai1i2i2i2i2hg:157oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i157R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:44oR1d768R2ad128d1024d256d1024d256d896d128d896d128d1024d0d1152d128d1152d128d1024d0d1024d0d1152hR3d384R4d256R5d0R6d128R7d-128R8d128R9d0R10d256R11i44R12d0R13d384R14ai1i2i2i2i2i1i2i2i2i2hg:156oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i156R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:43oR1d768R2ad128d896d256d896d256d768d384d768d384d640d256d640d256d512d128d512d128d640d0d640d0d768d128d768d128d896hR3d512R4d384R5d0R6d512R7d128R8d512R9d0R10d256R11i43R12d0R13d512R14ai1i2i2i2i2i2i2i2i2i2i2i2i2hg:155oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i155R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:42oR1d768R2ad128d512d128d384d0d384d0d512d128d512d256d640d256d512d128d512d128d640d256d640d384d512d384d384d256d384d256d512d384d512d128d768d128d640d0d640d0d768d128d768d384d768d384d640d256d640d256d768d384d768hR3d512R4d384R5d0R6d640R7d256R8d640R9d0R10d256R11i42R12d0R13d512R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:154oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i154R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:41oR1d768R2ad0d384d0d512d128d512d128d384d0d384d256d512d128d512d128d896d256d896d256d512d128d896d0d896d0d1024d128d1024d128d896hR3d384R4d256R5d0R6d640R7d0R8d640R9d0R10d256R11i41R12d0R13d384R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:153oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i153R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:40oR1d768R2ad256d384d128d384d128d512d256d512d256d384d128d512d0d512d0d896d128d896d128d512d256d1024d256d896d128d896d128d1024d256d1024hR3d384R4d256R5d0R6d640R7d0R8d640R9d0R10d256R11i40R12d0R13d384R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:152oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i152R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:39oR1d768R2ad128d384d0d384d0d640d128d640d128d384hR3d256R4d128R5d0R6d640R7d384R8d640R9d0R10d256R11i39R12d0R13d256R14ai1i2i2i2i2hg:151oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i151R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:38oR1d768R2ad384d769.024d128d769.024d128d894.976d384d894.976d384d769.024d640d1024d512d1024d512d896d384d896d384d1024d128d1024d128d896d0d896d0d768d128d768d128d640d0d640d0d512d128d512d128d384d384d384d384d512d128d512d128d640d384d640d384d768d512d768d512d640d640d640d640d768d512d768d512d896d640d896d640d1024hR3d768R4d640R5d0R6d640R7d0R8d640R9d0R10d256R11i38R12d0R13d768R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2hg:150oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i150R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:37oR1d768R2ad128d384d0d384d0d512d128d512d128d384d512d384d384d384d384d640d512d640d512d384d128d1024d256d1024d256d768d128d768d128d1024d256d768d384d768d384d640d256d640d256d768d512d896d512d1024d640d1024d640d896d512d896hR3d768R4d640R5d0R6d640R7d0R8d640R9d0R10d256R11i37R12d0R13d768R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:149oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i149R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:36oR1d768R2ad384d384d256d384d256d512d128d512d128d640d0d640d0d768d256d768d256d640d512d640d512d512d384d512d384d384d0d896d0d1024d256d1024d256d1152d384d1152d384d896d512d896d512d768d256d768d256d896d0d896hR3d640R4d512R5d0R6d640R7d-128R8d640R9d0R10d256R11i36R12d0R13d640R14ai1i2i2i2i2i2i2i2i2i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2hg:148oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i148R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:35oR1d768R2ad640d640d640d512d512d512d512d384d384d384d384d512d256d512d256d384d128d384d128d512d0d512d0d640d128d640d128d768d0d768d0d896d128d896d128d1024d256d1024d256d896d384d896d384d1024d512d1024d512d896d640d896d640d768d512d768d512d640d640d640d384d768d256d768d256d640d384d640d384d768hR3d768R4d640R5d0R6d640R7d0R8d640R9d0R10d256R11i35R12d0R13d768R14ai1i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i2i1i2i2i2i2hg:147oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i147R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:34oR1d768R2ad0d640d128d640d128d384d0d384d0d640d256d640d384d640d384d384d256d384d256d640hR3d512R4d384R5d0R6d640R7d384R8d640R9d0R10d256R11i34R12d0R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:146oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i146R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:33oR1d768R2ad128d384d0d384d0d768d128d768d128d384d128d896d0d896d0d1024d128d1024d128d896hR3d256R4d128R5d0R6d640R7d0R8d640R9d0R10d256R11i33R12d0R13d256R14ai1i2i2i2i2i1i2i2i2i2hg:145oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i145R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:32oR1d768R2ahR3d512R4d0R5d0R6d0R7d0R8d0R9d0R10d256R11i32R12d0R13d512R14ahg:144oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i144R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:143oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i143R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:255oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i255R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:142oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i142R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:254oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i254R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:141oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i141R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:253oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i253R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:140oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i140R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:252oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i252R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:139oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i139R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:251oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i251R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:138oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i138R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:250oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i250R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:137oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i137R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:249oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i249R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:136oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i136R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:248oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i248R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:135oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i135R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:247oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i247R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:134oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i134R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:246oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i246R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:133oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i133R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:245oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i245R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:132oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i132R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:244oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i244R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:131oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i131R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:243oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i243R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:130oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i130R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:242oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i242R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:129oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i129R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:241oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i241R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:128oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i128R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:240oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i240R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:127oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i127R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:239oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i239R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:126oR1d768R2ad128d384d128d512d256d512d256d384d128d384d0d640d128d640d128d512d0d512d0d640d384d512d512d512d512d384d384d384d384d512d256d640d384d640d384d512d256d512d256d640hR3d640R4d512R5d0R6d640R7d384R8d640R9d0R10d256R11i126R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:238oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i238R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:125oR1d768R2ad256d384d0d384d0d512d128d512d128d640d256d640d256d384d128d896d0d896d0d1024d256d1024d256d768d128d768d128d896d256d768d384d768d384d640d256d640d256d768hR3d512R4d384R5d0R6d640R7d0R8d640R9d0R10d256R11i125R12d0R13d512R14ai1i2i2i2i2i2i2i1i2i2i2i2i2i2i1i2i2i2i2hg:237oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i237R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:124oR1d768R2ad0d1024d128d1024d128d384d0d384d0d1024hR3d256R4d128R5d0R6d640R7d0R8d640R9d0R10d256R11i124R12d0R13d256R14ai1i2i2i2i2hg:236oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i236R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:123oR1d768R2ad128d384d128d640d256d640d256d512d384d512d384d384d128d384d0d768d128d768d128d640d0d640d0d768d128d1024d384d1024d384d896d256d896d256d768d128d768d128d1024hR3d512R4d384R5d0R6d640R7d0R8d640R9d0R10d256R11i123R12d0R13d512R14ai1i2i2i2i2i2i2i1i2i2i2i2i1i2i2i2i2i2i2hg:235oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i235R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:122oR1d768R2ad0d512d0d640d256d640d256d768d384d768d384d640d512d640d512d512d0d512d128d896d0d896d0d1024d512d1024d512d896d256d896d256d768d128d768d128d896hR3d640R4d512R5d0R6d512R7d0R8d512R9d0R10d256R11i122R12d0R13d640R14ai1i2i2i2i2i2i2i2i2i1i2i2i2i2i2i2i2i2hg:234oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i234R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:121oR1d768R2ad128d512d0d512d0d896d128d896d128d512d384d1024d384d1152d512d1152d512d512d384d512d384d896d128d896d128d1024d384d1024d128d1152d128d1280d384d1280d384d1152d128d1152hR3d640R4d512R5d0R6d512R7d-256R8d512R9d0R10d256R11i121R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2i1i2i2i2i2hg:233oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i233R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:120oR1d768R2ad0d512d0d640d128d640d128d512d0d512d384d512d256d512d256d640d384d640d384d512d256d640d128d640d128d896d256d896d256d640d128d896d0d896d0d1024d128d1024d128d896d384d1024d384d896d256d896d256d1024d384d1024hR3d512R4d384R5d0R6d512R7d0R8d512R9d0R10d256R11i120R12d0R13d512R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:232oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i232R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:119oR1d768R2ad128d512d0d512d0d768d128d768d128d512d512d768d640d768d640d512d512d512d512d768d384d512d256d512d256d768d384d768d384d512d128d1024d256d1024d256d768d128d768d128d1024d384d1024d512d1024d512d768d384d768d384d1024hR3d768R4d640R5d0R6d512R7d0R8d512R9d0R10d256R11i119R12d0R13d768R14ai1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:231oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i231R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:118oR1d768R2ad384d768d512d768d512d512d384d512d384d768d128d768d128d512d0d512d0d896d128d896d128d768d128d768d256d896d384d896d384d768d256d768d256d896d128d1024d256d1024d256d896d128d896d128d1024hR3d640R4d512R5d0R6d512R7d0R8d512R9d0R10d256R11i118R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i2i2i1i2i2i2i2i1i2i2i2i2hg:230oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i230R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:117oR1d768R2ad384d896d128d896d128d1024d512d1024d512d512d384d512d384d896d128d512d0d512d0d896d128d896d128d512hR3d640R4d512R5d0R6d512R7d0R8d512R9d0R10d256R11i117R12d0R13d640R14ai1i2i2i2i2i2i2i1i2i2i2i2hg:229oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i229R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:116oR1d768R2ad256d384d128d384d128d512d0d512d0d640d128d640d128d896d256d896d256d640d384d640d384d512d256d512d256d384d384d1024d384d896d256d896d256d1024d384d1024hR3d512R4d384R5d0R6d640R7d0R8d640R9d0R10d256R11i116R12d0R13d512R14ai1i2i2i2i2i2i2i2i2i2i2i2i2i1i2i2i2i2hg:228oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i228R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:115oR1d768R2ad128d512d128d640d0d640d0d768d256d768d256d640d512d640d512d512d128d512d0d896d0d1024d384d1024d384d896d512d896d512d768d256d768d256d896d0d896hR3d640R4d512R5d0R6d512R7d0R8d512R9d0R10d256R11i115R12d0R13d640R14ai1i2i2i2i2i2i2i2i2i1i2i2i2i2i2i2i2i2hg:227oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i227R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:114oR1d768R2ad384d512d256d512d256d640d384d640d384d512d128d768d256d768d256d640d128d640d128d512d0d512d0d1024d128d1024d128d768hR3d512R4d384R5d0R6d512R7d0R8d512R9d0R10d256R11i114R12d0R13d512R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2hg:226oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i226R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:113oR1d768R2ad128d894.976d384d894.976d384d641.024d128d641.024d128d894.976d128d640d128d512d512d512d512d1280d384d1280d384d1024d128d1024d128d896d0d896d0d640d128d640hR3d640R4d512R5d0R6d512R7d-256R8d512R9d0R10d256R11i113R12d0R13d640R14ai1i2i2i2i2i1i2i2i2i2i2i2i2i2i2i2hg:225oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i225R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hg:112oR1d768R2ad384d640d512d640d512d896d384d896d384d1024d128d1024d128d1280d0d1280d0d512d384d512d384d640d128d894.976d384d894.976d384d641.024d128d641.024d128d894.976hR3d640R4d512R5d0R6d512R7d-256R8d512R9d0R10d256R11i112R12d0R13d640R14ai1i2i2i2i2i2i2i2i2i2i2i1i2i2i2i2hg:224oR1d768R2ad64.512d1024d64.512d256d448.512d256d448.512d1024d64.512d1024d128d959.488d384d959.488d384d319.487d128d319.487d128d959.488hR3d512R4d448.512R5d64.512R6d768R7d0R8d703.488R9d0R10d256R11i224R12d64.512R13d512R14ai1i2i2i2i2i1i2i2i2i2hghy8:fontNamey5:04b03g
\ No newline at end of file
diff --git a/assets/general/goButton.png b/assets/general/goButton.png
new file mode 100644
index 0000000..38965e3
Binary files /dev/null and b/assets/general/goButton.png differ
diff --git a/assets/general/sky.png b/assets/general/sky.png
new file mode 100644
index 0000000..ecb68bb
Binary files /dev/null and b/assets/general/sky.png differ
diff --git a/assets/objects/enemies/foe02.png b/assets/objects/enemies/foe02.png
new file mode 100644
index 0000000..5e8e4c7
Binary files /dev/null and b/assets/objects/enemies/foe02.png differ
diff --git a/assets/objects/enemies/tesla1.png b/assets/objects/enemies/tesla1.png
new file mode 100644
index 0000000..bb01e6f
Binary files /dev/null and b/assets/objects/enemies/tesla1.png differ
diff --git a/assets/objects/enemies/tesla2.png b/assets/objects/enemies/tesla2.png
new file mode 100644
index 0000000..f01a390
Binary files /dev/null and b/assets/objects/enemies/tesla2.png differ
diff --git a/assets/objects/enemies/tesla3.png b/assets/objects/enemies/tesla3.png
new file mode 100644
index 0000000..c267db2
Binary files /dev/null and b/assets/objects/enemies/tesla3.png differ
diff --git a/assets/objects/player/plane01.png b/assets/objects/player/plane01.png
new file mode 100644
index 0000000..45ed6a8
Binary files /dev/null and b/assets/objects/player/plane01.png differ
diff --git a/assets/openfl.svg b/assets/openfl.svg
new file mode 100644
index 0000000..506f61d
--- /dev/null
+++ b/assets/openfl.svg
@@ -0,0 +1,17 @@
+
+
+
+
diff --git a/assets/rw.png b/assets/rw.png
new file mode 100644
index 0000000..a18113f
Binary files /dev/null and b/assets/rw.png differ
diff --git a/assets/rw.svg b/assets/rw.svg
new file mode 100644
index 0000000..572cd90
--- /dev/null
+++ b/assets/rw.svg
@@ -0,0 +1,26 @@
+
+
+
+
diff --git a/assets/rw2.png b/assets/rw2.png
new file mode 100644
index 0000000..57ec4ac
Binary files /dev/null and b/assets/rw2.png differ
diff --git a/assets/rw2.svg b/assets/rw2.svg
new file mode 100644
index 0000000..79efc9f
--- /dev/null
+++ b/assets/rw2.svg
@@ -0,0 +1,28 @@
+
+
+
+
diff --git a/assets/tiles/middle.png b/assets/tiles/middle.png
new file mode 100644
index 0000000..f77cd13
Binary files /dev/null and b/assets/tiles/middle.png differ
diff --git a/assets/tiles/middle2.png b/assets/tiles/middle2.png
new file mode 100644
index 0000000..afa0472
Binary files /dev/null and b/assets/tiles/middle2.png differ
diff --git a/assets/tiles/slopeDown.png b/assets/tiles/slopeDown.png
new file mode 100644
index 0000000..79b06e9
Binary files /dev/null and b/assets/tiles/slopeDown.png differ
diff --git a/assets/tiles/slopeUp.png b/assets/tiles/slopeUp.png
new file mode 100644
index 0000000..172fe76
Binary files /dev/null and b/assets/tiles/slopeUp.png differ
diff --git a/assets/tiles/top.png b/assets/tiles/top.png
new file mode 100644
index 0000000..90f33b8
Binary files /dev/null and b/assets/tiles/top.png differ
diff --git a/assets/tiles/top2.png b/assets/tiles/top2.png
new file mode 100644
index 0000000..03d5969
Binary files /dev/null and b/assets/tiles/top2.png differ
diff --git a/assets/tiles/tst1.png b/assets/tiles/tst1.png
new file mode 100644
index 0000000..8ec737b
Binary files /dev/null and b/assets/tiles/tst1.png differ
diff --git a/assets/tiles/tst4.png b/assets/tiles/tst4.png
new file mode 100644
index 0000000..9dfc54f
Binary files /dev/null and b/assets/tiles/tst4.png differ
diff --git a/assets/tiles/tstM.png b/assets/tiles/tstM.png
new file mode 100644
index 0000000..47b7f79
Binary files /dev/null and b/assets/tiles/tstM.png differ
diff --git a/assets/ui/gameOverText.png b/assets/ui/gameOverText.png
new file mode 100644
index 0000000..a1cc9c9
Binary files /dev/null and b/assets/ui/gameOverText.png differ
diff --git a/assets/ui/gameOverText.psd b/assets/ui/gameOverText.psd
new file mode 100644
index 0000000..41f0112
Binary files /dev/null and b/assets/ui/gameOverText.psd differ
diff --git a/assets/ui/joystickHead.png b/assets/ui/joystickHead.png
new file mode 100644
index 0000000..e95d64b
Binary files /dev/null and b/assets/ui/joystickHead.png differ
diff --git a/assets/ui/joystickHead.psd b/assets/ui/joystickHead.psd
new file mode 100644
index 0000000..1bc517e
Binary files /dev/null and b/assets/ui/joystickHead.psd differ
diff --git a/openfl-readme.txt b/openfl-readme.txt
new file mode 100644
index 0000000..035191d
--- /dev/null
+++ b/openfl-readme.txt
@@ -0,0 +1,68 @@
+About OpenFL
+
+ OpenFL is the successor of NME, for Haxe 3+.
+
+ Building a game or application with OpenFL is almost like writing for a single platform. However,
+ when you are ready to publish your application, you can choose between targets like iOS, webOS,
+ Android, Windows, Mac, Linux and Flash Player.
+
+ Instead of using the lowest common denominator between platforms with a "universal" runtime,
+ OpenFL projects are compiled as SWF bytecode or C++ applications, using the Haxe language compiler
+ and the standard C++ compiler toolchain for each platform.
+
+ Read more:
+ http://openfl.org/
+
+Project configuration, libraries, classpaths
+
+ OpenFL configuration is based on a XML file - it allows you very complex
+ configurations depending on the target platform. There is no GUI for it.
+
+ DO NOT modify FlashDevelop project properties as they will automatically be synchronized with the
+ XML when you modify it.
+
+Development
+
+ OpenFL is encouraging to develop using the Flash API (ie. flash.display.Sprite) as in ActionScript 3.
+
+ Just code like you would code a Flash application, with the limitation that you can only use
+ the drawing API, bitmaps (see below) and TextFields.
+
+ However test often all the platforms you plan to target!
+
+ In OpenFL 3.x, SWFs and videos aren't supported yet.
+
+Assets
+
+ Place all your images, sounds, fonts in /assets and access them in your code using the
+ global Assets class which abstracts assets management for all platforms:
+
+ var img = new Bitmap(Assets.getBitmapData("assets/my-image.png"));
+ addChild(img);
+
+ Tutorials:
+ https://github.com/openfl/openfl/wiki/Get-Started
+
+Debugging
+
+ By default your project targets Flash so you'll be able to add breakpoints and debug your app
+ like any AS3 project.
+ HTML5 target can be debugged in the browser - some browsers, like Chrome, support "script maps"
+ which let you interactively debug .hx code directly instead of the generated JS.
+ There is however no interactive debugger yet for native targets.
+
+Changing target platform
+
+ For OpenFL projects, an additional drop-down menu appears in the main toolbar where you can choose
+ a supported targets on Windows: flash, html5, windows, neko, android, webos, blackberry.
+ You can also manually enter a custom target not in the list.
+
+ Attention, for native targets you'll need to install additional compilers & SDKs. The compiler
+ will tell you in the Output panel what command to execute for that. More information here:
+ https://github.com/openfl/openfl/wiki/Get-Started
+
+Tips:
+ - in C++ expect first compilation to be very long as it first compiles the whole OpenFL API,
+ - if a change is not taken in account, delete everything in /bin to start a fresh compilation,
+ - on mobile, Bitmap blitting is NOT performant,
+ - use spritesheets and Tilesheet.drawTiles for optimal rendering performance.
diff --git a/src/FPS.hx b/src/FPS.hx
new file mode 100644
index 0000000..e2d899b
--- /dev/null
+++ b/src/FPS.hx
@@ -0,0 +1,38 @@
+import flash.events.Event;
+import flash.Lib;
+import flash.text.TextField;
+import flash.text.TextFormat;
+
+class FPS extends TextField
+{
+ var times:Array;
+
+ public function new(inX:Float=10.0, inY:Float=10.0, inCol:Int = 0x000000)
+ {
+ super();
+ x = inX;
+ y = inY;
+ selectable = false;
+ embedFonts = true;
+ defaultTextFormat = new TextFormat(FontManager.mainFont.fontName, 16, 0, true);
+ text = "FPS:";
+ textColor = inCol;
+ times = [];
+ addEventListener(Event.ENTER_FRAME, enterFrame);
+ }
+
+ private function enterFrame(e:Event):Void
+ {
+ var now = Lib.getTimer () / 1000;
+ times.push(now);
+ while(times[0];
+ static private var socketConnected:Bool;
+
+ static public function connectTracer():Void
+ {
+ messageQueue = [];
+
+ xmlSocket = new XMLSocket();
+ xmlSocket.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
+ xmlSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
+ xmlSocket.addEventListener(Event.CONNECT, onConnect);
+ try
+ {
+ xmlSocket.connect('localhost', 4442);
+ }
+ catch (e:Dynamic)
+ {
+
+ }
+ }
+
+ static public function disconnectTracer():Void
+ {
+ if (xmlSocket != null && xmlSocket.connected)
+ {
+ xmlSocket.close();
+ }
+ }
+
+ static private function onConnect(e:Event):Void
+ {
+ socketConnected = true;
+ add("Connected to socket");
+ while (messageQueue.length > 0) {
+ xmlSocket.send(messageQueue.shift());
+ }
+ }
+
+ static private function onSecurityError(e:SecurityErrorEvent):Void
+ {
+
+ }
+
+ static private function onIOError(e:IOErrorEvent):Void
+ {
+
+ }
+
+ static public function add(string:String, type:String = "SYSTEM"):Void
+ {
+ var splitMessage:Array = string.split("\n");
+
+ if (xmlSocket == null) {
+ connectTracer();
+ }
+
+ var message:String = '!SOS';
+ if (socketConnected)
+ {
+ try
+ {
+ xmlSocket.send(message);
+ }
+ catch (e:Dynamic)
+ {
+
+ }
+ }
+ else
+ {
+ messageQueue.push(message);
+ }
+
+ while (messageQueue.length > 1000)
+ {
+ messageQueue.shift();
+ }
+ }
+
+ static public function objectToString(target:Dynamic, ?depth:Int = 0):String
+ {
+ var tab:String = ' ';
+ for (i in 0...depth)
+ {
+ tab += ' ';
+ }
+
+ var out : String = '';
+
+ /*
+ var item:Dynamic;
+ var dat:Dynamic;
+ var objectToDescribe:String;
+ var enter:String = '\n';
+ for (item in target)
+ {
+ dat = target[item];
+ if (typeof(dat) == 'object')
+ {
+ out += tab+'['+item+']' + enter;
+ objectToDescribe = objectToString(dat, depth+1);
+ out += (objectToDescribe != '' ? objectToDescribe : tab + '...') + enter;
+ out += tab+'[/'+item+']' + enter;
+ }
+ }
+
+ var step:Int = 0;
+ for (item in target) {
+ dat = target[item];
+ if (typeof(dat) != 'object') {
+ if (step) { out += enter; }
+ out += tab+''+item+' = '+dat;
+ step++;
+ }
+ }
+ */
+ return out;
+ }
+
+ static public function sosTrace(data:String, ?logLevel:String = TRACE):Void
+ {
+
+ /*
+ for (var i:int = 0; i < arguments.length; i++)
+ {
+ argument = arguments[i];
+ if (argument == null )
+ {
+ string += null;
+ }
+ else if (typeof(argument) == 'object')
+ {
+ string += '\n';
+ string += "[" + getQualifiedClassName(argument) + "]";
+ string += '\n' + SOSLog.objectToString(argument) + '\n';
+ string += "[/" + getQualifiedClassName(argument) + "]";
+ } else
+ {
+ string += argument;
+ if (i < arguments.length - 1) {
+ string += ', ';
+ }
+ }
+ }*/
+ SOSLog.add(data, logLevel);
+ }
+ #else
+ static public function sosTrace(data:String, ?logLevel:String = TRACE):Void
+ {
+ trace(data);
+ }
+ #end
+}
\ No newline at end of file
diff --git a/src/ScreenPad.hx b/src/ScreenPad.hx
new file mode 100644
index 0000000..b6a5829
--- /dev/null
+++ b/src/ScreenPad.hx
@@ -0,0 +1,88 @@
+package ;
+import flash.display.Bitmap;
+import flash.display.BitmapData;
+import flash.display.Sprite;
+import flash.events.Event;
+import flash.events.MouseEvent;
+import openfl.Assets;
+
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+
+class ScreenPad extends Sprite
+{
+ static public inline var WIDTH:Int = 128;
+ static public inline var HEIGHT:Int = 128;
+ static public inline var SIDE_PAD:Int = 16;
+
+ public var xMagnitude:Float;
+ public var yMagnitude:Float;
+ private var headBitmap:Bitmap;
+ private var mouseDown:Bool;
+ private var headContainer:Sprite;
+
+ public function new()
+ {
+ super();
+ var backgroundBitmapData:BitmapData = new BitmapData(WIDTH,HEIGHT, true, 0);
+ var backgroundSource:Sprite = new Sprite();
+ backgroundSource.graphics.lineStyle(2, 0, 0.6, true);
+ backgroundSource.graphics.beginFill(0, 0.2);
+ backgroundSource.graphics.drawRoundRect(1, 1, WIDTH-2, HEIGHT-2, WIDTH/4, HEIGHT/4);
+ backgroundSource.graphics.endFill();
+ backgroundBitmapData.draw(backgroundSource);
+ addChild(new Bitmap(backgroundBitmapData));
+
+ headContainer = new Sprite();
+ headContainer.x = WIDTH / 2;
+ headContainer.y = HEIGHT / 2;
+ addChild(headContainer);
+
+ headBitmap = new Bitmap(Assets.getBitmapData("assets/ui/joystickHead.png"));
+ headBitmap.x = -headBitmap.width / 2;
+ headBitmap.y = -headBitmap.height/ 2;
+ headContainer.addChild(headBitmap);
+
+ addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
+ addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
+ //TODO cleanup routine on removed from stage
+ }
+
+ private function addedToStageHandler(e:Event):Void
+ {
+ removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
+ stage.addEventListener(MouseEvent.MOUSE_UP, stage_mouseUpHandler);
+ }
+
+ private function mouseDownHandler(e:MouseEvent):Void
+ {
+ mouseDown = true;
+ }
+
+ private function stage_mouseUpHandler(e:MouseEvent):Void
+ {
+ mouseDown = false;
+ }
+
+ public function update(dTime:Float):Void
+ {
+ if (mouseDown)
+ {
+ headContainer.x = Math.min(Math.max(mouseX, SIDE_PAD), WIDTH - SIDE_PAD);
+ headContainer.y = Math.min(Math.max(mouseY, SIDE_PAD), HEIGHT - SIDE_PAD);
+ xMagnitude = (mouseX - WIDTH / 2) / ((WIDTH - SIDE_PAD * 2 - 2) / 2);
+ yMagnitude = (mouseY - HEIGHT/ 2) / ((HEIGHT- SIDE_PAD * 2 - 2) / 2);
+ }
+ else
+ {
+ headContainer.x += (WIDTH / 2 - headContainer.x) * dTime * 10;
+ headContainer.y += (HEIGHT / 2 - headContainer.y) * dTime * 10;
+ xMagnitude = 0;
+ yMagnitude = 0;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/assets/EntityGraphicsAsset.hx b/src/assets/EntityGraphicsAsset.hx
new file mode 100644
index 0000000..310f5cc
--- /dev/null
+++ b/src/assets/EntityGraphicsAsset.hx
@@ -0,0 +1,93 @@
+package assets;
+import flash.display.BitmapData;
+import flash.geom.Point;
+import flash.geom.Rectangle;
+import haxe.ds.IntMap.IntMap;
+import haxe.ds.StringMap.StringMap;
+import haxe.ds.StringMap.StringMap;
+import openfl.Assets;
+
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class EntityGraphicsAsset
+{
+ public var assetID:String;
+ public var spriteSheet:BitmapData;
+ public var frameRectangles:Array;
+ public var tileSheetRectangles:Array;
+ public var tileSheetFrameID:Array;
+ public var sizeCorrection:Point;
+ public var assetFrameByName:StringMap;
+
+ public function new(assetID:String)
+ {
+ this.assetID = assetID;
+ frameRectangles = new Array();
+ tileSheetFrameID = new Array();
+ tileSheetRectangles = new Array();
+ assetFrameByName = new StringMap();
+ }
+
+ public function initializeFromAssetNames(namesArray:Array):EntityGraphicsAsset
+ {
+ var sourceAssets:Array = [];
+ var numAssets:Int = namesArray.length;
+ var maxWidth:Int = 0;
+ var maxHeight:Int = 0;
+ for (i in 0...numAssets)
+ {
+ //trace(namesArray[i]);
+ var asset:BitmapData = Assets.getBitmapData(namesArray[i]);
+ maxWidth = Std.int(Math.max(maxWidth, asset.width));
+ maxHeight = Std.int(Math.max(maxHeight, asset.height));
+ sourceAssets.push(asset);
+ assetFrameByName.set(namesArray[i], i);
+ }
+
+ //TODO only for non-flash targets
+ #if (!flash)
+ maxWidth = Math.ceil(Std.int(Math.max(maxWidth, maxHeight))/2)*2;
+ maxHeight = maxWidth;
+ #end
+
+ sizeCorrection = new Point(-maxWidth / 2, -maxHeight/2);
+
+ frameRectangles = new Array();
+
+ #if flash
+ spriteSheet = new BitmapData(numAssets * maxWidth, numAssets*maxHeight, true, 0x0);
+ #else
+ spriteSheet = new BitmapData(numAssets * maxWidth, numAssets*maxHeight, true, 0x0);
+ #end
+
+ for (i in 0...numAssets)
+ {
+ var destinationRectangle:Rectangle = new Rectangle(i * maxWidth, 0, maxWidth, maxHeight);
+ //trace(destinationRectangle);
+ frameRectangles.push(destinationRectangle);
+ var sourceWidth:Int = sourceAssets[i].width;
+ var sourceHeight:Int = sourceAssets[i].height;
+ spriteSheet.copyPixels(sourceAssets[i], new Rectangle(0, 0, sourceWidth, sourceHeight), new Point(destinationRectangle.x + Std.int((maxWidth - sourceWidth) / 2), destinationRectangle.y + Std.int((maxHeight - sourceHeight) / 2)));
+ }
+
+ return this;
+ }
+
+ public function getFrameByAssetName(assetName:String):Int
+ {
+ var assetFrame:Null = assetFrameByName.get(assetName);
+ if (assetFrame != null)
+ {
+ return assetFrame;
+ }
+ return 0;
+ }
+
+ public function clear()
+ {
+ spriteSheet.dispose();
+ }
+
+}
\ No newline at end of file
diff --git a/src/assets/GraphicsLibrary.hx b/src/assets/GraphicsLibrary.hx
new file mode 100644
index 0000000..829f654
--- /dev/null
+++ b/src/assets/GraphicsLibrary.hx
@@ -0,0 +1,183 @@
+package assets;
+
+import flash.display.Bitmap;
+import flash.display.BitmapData;
+import openfl.display.Tilesheet;
+import flash.geom.Matrix;
+import flash.geom.Point;
+import flash.geom.Rectangle;
+import openfl.Assets;
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class GraphicsLibrary
+{
+ private static var explosionAsset:EntityGraphicsAsset;
+
+ private static var playerAsset:EntityGraphicsAsset;
+
+ private static var tilesAsset:EntityGraphicsAsset;
+
+ private static var bulletAsset:EntityGraphicsAsset;
+
+ private static var enemyBulletAsset:EntityGraphicsAsset;
+
+ private static var teslaFlyerAsset:EntityGraphicsAsset;
+
+ static private var bulletHitAsset:EntityGraphicsAsset;
+
+ static private var debriesAsset:EntityGraphicsAsset;
+
+ static private var baloonAsset:EntityGraphicsAsset;
+
+ static private var railgunTrailAsset:EntityGraphicsAsset;
+
+ static private var smokeAsset:EntityGraphicsAsset;
+
+ static public var tilesheet:Tilesheet;
+
+ public function GraphicsLibrary()
+ {
+
+ }
+
+ public static function initialize():Void
+ {
+ explosionAsset = new EntityGraphicsAsset("explosion").initializeFromAssetNames(["assets/effects/explosion1/1.png", "assets/effects/explosion1/2.png", "assets/effects/explosion1/3.png", "assets/effects/explosion1/4.png", "assets/effects/explosion1/5.png"]);
+ playerAsset = new EntityGraphicsAsset("player").initializeFromAssetNames(["assets/objects/player/plane01.png"]);
+ tilesAsset = new EntityGraphicsAsset("tile").initializeFromAssetNames(["assets/tiles/top.png", "assets/tiles/middle.png", "assets/tiles/slopeUp.png", "assets/tiles/slopeDown.png", "assets/tiles/middle2.png", "assets/tiles/top2.png"]);
+
+ bulletAsset = new EntityGraphicsAsset("bullet").initializeFromAssetNames(["assets/effects/projectiles/beam02.png"]);
+ enemyBulletAsset = new EntityGraphicsAsset("enemyBullet").initializeFromAssetNames(["assets/effects/projectiles/beam01.png","assets/effects/projectiles/enemyBalloonBullet.png"]);
+ bulletHitAsset = new EntityGraphicsAsset("bulletHit").initializeFromAssetNames(["assets/effects/bulletHit/bulletHit.png"]);
+ teslaFlyerAsset = new EntityGraphicsAsset("teslaFlyer").initializeFromAssetNames(["assets/objects/enemies/tesla1.png", "assets/objects/enemies/tesla2.png", "assets/objects/enemies/tesla3.png"]);
+ baloonAsset = new EntityGraphicsAsset("baloon").initializeFromAssetNames(["assets/objects/enemies/foe02.png"]);
+ smokeAsset = new EntityGraphicsAsset("smoke").initializeFromAssetNames(["assets/effects/smoke/smoke01.png", "assets/effects/smoke/smoke02.png", "assets/effects/smoke/smoke03.png", "assets/effects/smoke/smoke04.png", "assets/effects/smoke/smoke05.png"]);
+ debriesAsset = new EntityGraphicsAsset("debries").initializeFromAssetNames(["assets/effects/debries/debries1.png", "assets/effects/debries/debries2.png", "assets/effects/debries/debries3.png"]);
+
+ #if (!android && !iphone)
+ railgunTrailAsset = new EntityGraphicsAsset("railgunTrail").initializeFromAssetNames(["assets/effects/projectiles/railgunTrail.png"]);
+ #end
+
+ #if (android || iphone)
+ createTilesheet([explosionAsset, playerAsset, tilesAsset, bulletAsset, enemyBulletAsset, bulletHitAsset, teslaFlyerAsset, baloonAsset, smokeAsset, debriesAsset]);
+ #elseif cpp
+ createTilesheet([explosionAsset, playerAsset, tilesAsset, debriesAsset, bulletAsset, enemyBulletAsset, bulletHitAsset, teslaFlyerAsset, baloonAsset, railgunTrailAsset, smokeAsset]);
+ #end
+ }
+
+ static private function createTilesheet(assetArray:Array):Void
+ {
+ var maxHeight:Float = 0;
+ var totalWidth:Float = 0;
+ var assetFrameID:Int = 0;
+ for (i in 0...assetArray.length)
+ {
+ var asset:EntityGraphicsAsset = assetArray[i];
+
+ for (j in 0...asset.frameRectangles.length)
+ {
+ asset.tileSheetFrameID.push(assetFrameID);
+ var tilesheetRect:Rectangle = asset.frameRectangles[j].clone();
+ tilesheetRect.x += totalWidth;
+ asset.tileSheetRectangles.push(tilesheetRect);
+ assetFrameID++;
+ }
+ maxHeight = Math.max(maxHeight, asset.spriteSheet.height);
+ totalWidth += asset.spriteSheet.width;
+ }
+
+ var bitmapData:BitmapData = new BitmapData(Std.int(totalWidth), Std.int(maxHeight), true, 0);
+
+ var currentX:Int = 0;
+ for (i in 0...assetArray.length)
+ {
+ var asset:EntityGraphicsAsset = assetArray[i];
+ bitmapData.copyPixels(asset.spriteSheet, new Rectangle(0, 0, asset.spriteSheet.width, asset.spriteSheet.height), new Point(currentX, 0));
+ currentX += asset.spriteSheet.width;
+ asset.clear();
+ }
+
+ tilesheet = new Tilesheet(bitmapData);
+ for (i in 0...assetArray.length)
+ {
+ var asset:EntityGraphicsAsset = assetArray[i];
+ for (j in 0...asset.tileSheetRectangles.length)
+ {
+ tilesheet.addTileRect(asset.tileSheetRectangles[j]);
+ }
+ }
+ }
+
+ public static function getExplosion1():EntityGraphicsAsset
+ {
+ return explosionAsset;
+ }
+
+ public static function getPlayerShip():EntityGraphicsAsset
+ {
+ return playerAsset;
+
+ /*if (playerAsset != null)
+ {
+ return playerAsset;
+ }
+
+ var bd:BitmapData = new BitmapData(120, 50, true, 0x00000000);
+ var playerBitmap:BitmapData = Assets.getBitmapData("assets/objects/player/plane01.png");
+ bd.copyPixels(playerBitmap, new Rectangle(0, 0, 120, 50), new Point(0, 0));
+
+ playerAsset = new EntityGraphicsAsset();
+ playerAsset.spriteSheet = bd;
+ playerAsset.frameRectangles = [new Rectangle(0, 0, 120, 50)];
+ playerAsset.sizeCorrection = new Point( -60, -25);
+ return playerAsset;*/
+ }
+
+ public static function getTiles():EntityGraphicsAsset
+ {
+ return tilesAsset;
+ }
+
+ public static function getDebries():EntityGraphicsAsset
+ {
+ return debriesAsset;
+ }
+
+ public static function getBullet():EntityGraphicsAsset
+ {
+ return bulletAsset;
+ }
+
+ public static function getEnemyBullet():EntityGraphicsAsset
+ {
+ return enemyBulletAsset;
+ }
+
+ public static function getBulletHit():EntityGraphicsAsset
+ {
+ return bulletHitAsset;
+ }
+
+ public static function getTeslaFlyer():EntityGraphicsAsset
+ {
+ return teslaFlyerAsset;
+ }
+
+ public static function getBaloon():EntityGraphicsAsset
+ {
+ return baloonAsset;
+ }
+
+ public static function getRailgunTrail():EntityGraphicsAsset
+ {
+ return railgunTrailAsset;
+ }
+
+ static public function getSmoke()
+ {
+ return smokeAsset;
+ }
+
+}
\ No newline at end of file
diff --git a/src/com/sphaeraobscura/keyboard/KeyKeeper.hx b/src/com/sphaeraobscura/keyboard/KeyKeeper.hx
new file mode 100644
index 0000000..6bd4662
--- /dev/null
+++ b/src/com/sphaeraobscura/keyboard/KeyKeeper.hx
@@ -0,0 +1,65 @@
+package com.sphaeraobscura.keyboard;
+import flash.display.Stage;
+import flash.events.Event;
+import flash.events.EventDispatcher;
+import flash.events.KeyboardEvent;
+
+/**
+ * ...
+ * @author Dimonte
+ */
+class KeyKeeper extends EventDispatcher
+{
+ private var _stage:Stage;
+ private var _keysPressed:Array;
+
+ public function new(stage:Stage)
+ {
+ super();
+ _stage = stage;
+ initKeeper();
+ }
+
+ private function initKeeper():Void
+ {
+ _keysPressed = new Array();
+ _stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler, false);
+ _stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler, false);
+ _stage.addEventListener(Event.DEACTIVATE, deactivateHandler, false);
+ }
+
+ private function keyDownHandler(e:KeyboardEvent):Void
+ {
+ if (!_keysPressed[e.keyCode])
+ {
+ dispatchEvent(new KeyKeeperEvent(KeyKeeperEvent.KEY_DOWN, e.keyCode));
+ }
+ _keysPressed[e.keyCode] = true;
+ }
+
+ private function keyUpHandler(e:KeyboardEvent):Void
+ {
+ if (_keysPressed[e.keyCode])
+ {
+ dispatchEvent(new KeyKeeperEvent(KeyKeeperEvent.KEY_UP, e.keyCode));
+ }
+ _keysPressed[e.keyCode] = false;
+ }
+
+ private function deactivateHandler(e:Event):Void
+ {
+ for (i in 0..._keysPressed.length)
+ {
+ if (_keysPressed[i])
+ {
+ dispatchEvent(new KeyKeeperEvent(KeyKeeperEvent.KEY_UP, i));
+ }
+ _keysPressed[i] = false;
+ }
+ }
+
+ public function isDown(keyCode:Int):Bool
+ {
+ return _keysPressed[keyCode];
+ }
+}
\ No newline at end of file
diff --git a/src/com/sphaeraobscura/keyboard/KeyKeeperEvent.hx b/src/com/sphaeraobscura/keyboard/KeyKeeperEvent.hx
new file mode 100644
index 0000000..bdce3e8
--- /dev/null
+++ b/src/com/sphaeraobscura/keyboard/KeyKeeperEvent.hx
@@ -0,0 +1,28 @@
+package com.sphaeraobscura.keyboard;
+import flash.events.Event;
+
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+
+class KeyKeeperEvent extends Event
+{
+
+ static public inline var KEY_DOWN:String = "keyDown";
+ static public inline var KEY_UP:String = "keyUp";
+
+ public var keyCode:Int;
+
+ public function new(type:String, keyCode:Int, bubbles:Bool = false, cancelable:Bool = false)
+ {
+ this.keyCode = keyCode;
+ super(type, bubbles, cancelable);
+ }
+
+ override public function clone():Event
+ {
+ return new KeyKeeperEvent(type, keyCode, bubbles, cancelable);
+ }
+
+}
\ No newline at end of file
diff --git a/src/dataStructures/DLL.hx b/src/dataStructures/DLL.hx
new file mode 100644
index 0000000..132ee55
--- /dev/null
+++ b/src/dataStructures/DLL.hx
@@ -0,0 +1,74 @@
+package dataStructures;
+
+
+/**
+ * ...
+ * @author Dimonte
+ */
+class DLL
+{
+ public var _head:DLLNode;
+ public var _tail:DLLNode;
+
+ public function new()
+ {
+ }
+
+ public function head():DLLNode
+ {
+ return _head;
+ }
+
+ public function append(object:Dynamic):DLLNode
+ {
+ var dllNode:DLLNode = new DLLNode();
+ dllNode.val = object;
+ if (_head == null)
+ {
+ _head = dllNode;
+ _tail = dllNode;
+ } else {
+ _tail.next = dllNode;
+ dllNode.previous = _tail;
+ _tail = dllNode;
+ }
+ return dllNode;
+ }
+
+ public function remove(node:DLLNode):Void
+ {
+ if (node == _head) {
+ _head = _head.next;
+ }
+ if (node == _tail) {
+ _tail = _tail.previous;
+ }
+ if (node.next != null)
+ {
+ node.next.previous = node.previous;
+ }
+ if (node.previous != null)
+ {
+ node.previous.next = node.next;
+ }
+ }
+
+ public function clear():Void
+ {
+ _tail = null;
+ _head = null;
+ }
+
+ public function getLength():Int
+ {
+ var length:Int = 0;
+ var node:DLLNode = _head;
+ while (node != null)
+ {
+ length++;
+ node = node.next;
+ }
+ return length;
+ }
+
+}
\ No newline at end of file
diff --git a/src/dataStructures/DLLNode.hx b/src/dataStructures/DLLNode.hx
new file mode 100644
index 0000000..74626cc
--- /dev/null
+++ b/src/dataStructures/DLLNode.hx
@@ -0,0 +1,31 @@
+package dataStructures;
+
+/**
+ * ...
+ * @author Dimonte
+ */
+class DLLNode
+{
+
+ public var next:DLLNode;
+ public var previous:DLLNode;
+ public var val:Dynamic;
+
+ public function new()
+ {
+
+ }
+
+ public function remove():Void
+ {
+ if (next != null)
+ {
+ next.previous = previous;
+ }
+ if (previous != null)
+ {
+ previous.next = next;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/Bullet.hx b/src/game/Bullet.hx
new file mode 100644
index 0000000..0743ac5
--- /dev/null
+++ b/src/game/Bullet.hx
@@ -0,0 +1,80 @@
+package game;
+
+import assets.GraphicsLibrary;
+import sphaeraGravita.collision.PhysicalBody;
+import sphaeraGravita.shapes.BaseShape;
+import game.GameEntity;
+import sphaeraGravita.shapes.CircleShape;
+import sphaeraGravita.shapes.Polygon;
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class Bullet extends GameEntity
+{
+ private var timePassedSinceLastUpdate:Float;
+
+ public function new(world:GameWorld)
+ {
+ super(world);
+
+ type = EntityType.PLAYER_BULLET;
+
+ graphicsAsset = GraphicsLibrary.getBullet();
+
+ collisionCategory = CollisionCategory.PLAYER_BULLET;
+ collisionMask = CollisionCategory.TILE | CollisionCategory.ENEMY;
+ unguidedProjectile = true;
+ gridBound = true;
+ /*
+ var s:Polygon = new Polygon();
+ s.setAsBox(1, 1);
+ /*/
+ var s:CircleShape = new CircleShape(0,0,6);
+ //*/
+ s.sensor = true;
+ addShape(s);
+ init();
+ }
+
+ override public function reset():Void
+ {
+ super.reset();
+ }
+
+ override public function reactToCollision(collidingBody:PhysicalBody, selfShape:BaseShape, otherShape:BaseShape):Void
+ {
+ cast(collidingBody, GameEntity).recieveDamage(12);
+
+ var bh:GameEntity = world.getReusableEntityByType(EntityType.BULLET_HIT);
+ bh.reset();
+ bh.x = x;
+ bh.y = y;
+ world.addParticle(bh);
+
+ dead = true;
+ }
+
+ override public function update(dTime:Float):Void
+ {
+ super.update(dTime);
+ timePassedSinceLastUpdate += dTime;
+ while (timePassedSinceLastUpdate > 0.035)
+ {
+ timePassedSinceLastUpdate-= 0.035;
+ speed.y *= 0.98;
+ }
+
+ #if (!android && !iphone)
+ if (Math.random() < 6*dTime)
+ {
+ var trail:GameEntity = world.getReusableEntityByType(EntityType.RAILGUN_TRAIL);
+ trail.reset();
+ trail.position = position.clone();
+ trail.speed = speed.clone();
+ world.addParticle(trail);
+ }
+ #end
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/BulletHit.hx b/src/game/BulletHit.hx
new file mode 100644
index 0000000..8b2c2ac
--- /dev/null
+++ b/src/game/BulletHit.hx
@@ -0,0 +1,40 @@
+package game;
+import assets.GraphicsLibrary;
+
+//import assets.GraphicsLibrary;
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class BulletHit extends GameEntity
+{
+ private var counter:Float;
+
+ public function new(world:GameWorld)
+ {
+ super(world);
+ counter = 0;
+ type = EntityType.BULLET_HIT;
+ graphicsAsset = GraphicsLibrary.getBulletHit();
+ gridBound = true;
+ unguidedProjectile = true;
+ init();
+ }
+
+ override public function reset():Void
+ {
+ super.reset();
+ counter = 0;
+ }
+
+ override public function update(dTime:Float):Void
+ {
+ super.update(dTime);
+ counter+=dTime;
+ if (counter > 0.2)
+ {
+ dead = true;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/CollisionCategory.hx b/src/game/CollisionCategory.hx
new file mode 100644
index 0000000..72aaf5d
--- /dev/null
+++ b/src/game/CollisionCategory.hx
@@ -0,0 +1,19 @@
+package game;
+
+/**
+ * ...
+ * @author Dimonte
+ */
+class CollisionCategory
+{
+ public static inline var INHERIT:Int = 0x00000000;
+
+ public static inline var PLAYER:Int = 0x00000001;
+ public static inline var TILE:Int = 0x00000002;
+ public static inline var LAND_OBJECT:Int = 0x00000004;
+ public static inline var ENEMY:Int = 0x00000008;
+ public static inline var PLAYER_BULLET:Int = 0x00000010;
+ public static inline var ENEMY_BULLET:Int = 0x00000020;
+ public static inline var PARTICLE:Int = 0x00000040;
+ static public inline var IGNORE:Int = 0x10000000;
+}
\ No newline at end of file
diff --git a/src/game/Debries.hx b/src/game/Debries.hx
new file mode 100644
index 0000000..17b190d
--- /dev/null
+++ b/src/game/Debries.hx
@@ -0,0 +1,96 @@
+package game;
+
+//import assets.GraphicsLibrary;
+import assets.GraphicsLibrary;
+import sphaeraGravita.collision.PhysicalBody;
+import sphaeraGravita.shapes.BaseShape;
+import game.GameEntity;
+import sphaeraGravita.shapes.CircleShape;
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class Debries extends GameEntity
+{
+ private var score:Int;
+
+ public function new(world:GameWorld)
+ {
+ super(world);
+
+ type = EntityType.DEBRIES;
+
+ graphicsAsset = GraphicsLibrary.getDebries();
+
+ collisionCategory = CollisionCategory.PARTICLE;
+
+ gridBound = true;
+ unguidedProjectile = true;
+
+ bounceFactor = 0.5;
+ frictionFactor = 1;
+
+ selectGraphicsAndScore();
+
+ var shape:CircleShape = new CircleShape(0, 0, 6);
+ shape.collisionMask = CollisionCategory.TILE;
+ addShape(shape);
+
+ var sensorShape:CircleShape = new CircleShape(0, 0, 6);
+ sensorShape.sensor = true;
+ sensorShape.collisionMask = CollisionCategory.PLAYER;
+ addShape(sensorShape);
+ init();
+ }
+
+ override public function reset():Void
+ {
+ super.reset();
+ collisionMask = CollisionCategory.TILE | CollisionCategory.PLAYER;
+ selectGraphicsAndScore();
+ }
+
+ override public function update(dTime:Float):Void
+ {
+ speed.y += 400*dTime;
+ }
+
+ override public function reactToCollision(collidingBody:PhysicalBody, selfShape:BaseShape, otherShape:BaseShape):Void
+ {
+ super.reactToCollision(collidingBody, selfShape, otherShape);
+
+ if (collidingBody.collisionCategory == CollisionCategory.PLAYER)
+ {
+ world.score += score;
+ dead = true;
+ return;
+ }
+
+ speed.x *= 0.2;
+ if (speed.y <= 0)
+ {
+ speed.y = Math.min(speed.y, -5);
+ }
+ collisionMask = CollisionCategory.PLAYER;
+ }
+
+ private function selectGraphicsAndScore():Void
+ {
+ if (Math.random() > 0.3)
+ {
+ frameRectNum = 2;
+ score = 100;
+ }
+ else if (Math.random() > 0.3)
+ {
+ frameRectNum = 0;
+ score = 75;
+ }
+ else
+ {
+ frameRectNum = 1;
+ score = 50;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/EnemyBullet.hx b/src/game/EnemyBullet.hx
new file mode 100644
index 0000000..2e44eeb
--- /dev/null
+++ b/src/game/EnemyBullet.hx
@@ -0,0 +1,55 @@
+package game;
+
+import assets.GraphicsLibrary;
+import sphaeraGravita.collision.PhysicalBody;
+import sphaeraGravita.shapes.BaseShape;
+import sphaeraGravita.shapes.CircleShape;
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class EnemyBullet extends GameEntity
+{
+ public var bulletDamage:Int;
+
+ public function new(world:GameWorld)
+ {
+ bulletDamage = 20;
+
+ super(world);
+
+ type = EntityType.ENEMY_BULLET;
+
+ graphicsAsset = GraphicsLibrary.getEnemyBullet();
+
+ collisionCategory = CollisionCategory.ENEMY_BULLET;
+ collisionMask = CollisionCategory.TILE | CollisionCategory.PLAYER;
+ unguidedProjectile = true;
+ gridBound = true;
+ /*
+ var s:Polygon = new Polygon();
+ s.setAsBox(1, 1);
+ /*/
+ var s:CircleShape = new CircleShape(0,0,6);
+ //*/
+ s.sensor = true;
+ addShape(s);
+ init();
+ }
+
+ override public function reactToCollision(collidingBody:PhysicalBody, selfShape:BaseShape, otherShape:BaseShape):Void
+ {
+ cast(collidingBody, GameEntity).recieveDamage(bulletDamage);
+ var bh:GameEntity = world.getReusableEntityByType(EntityType.BULLET_HIT);
+ bh.x = x;
+ bh.y = y;
+ world.addParticle(bh);
+ dead = true;
+ }
+
+ override public function update(dTime:Float):Void
+ {
+ super.update(dTime);
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/EnemyShip.hx b/src/game/EnemyShip.hx
new file mode 100644
index 0000000..d121f9f
--- /dev/null
+++ b/src/game/EnemyShip.hx
@@ -0,0 +1,250 @@
+package game;
+
+import assets.GraphicsLibrary;
+import game.behaviours.BaloonBehaviour;
+import game.behaviours.BasicBehaviour;
+import game.behaviours.IBehaviour;
+import game.behaviours.KamikazeBaloonBehaviour;
+import game.behaviours.TeslaBehaviourFrontalAssault;
+import game.behaviours.TeslaBehaviourRam;
+import sphaeraGravita.collision.PhysicalBody;
+import sphaeraGravita.shapes.BaseShape;
+import game.GameEntity;
+import sphaeraGravita.shapes.CircleShape;
+import sphaeraGravita.shapes.Polygon;
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class EnemyShip extends GameEntity
+{
+ public static inline var TESLA:String = "tesla";
+ public static inline var BALOON:String = "baloon";
+
+ public var shipType:String;
+ public var shotDown:Bool;
+ private var counter:Float;
+ public var behaviour:IBehaviour;
+
+ private var smokeCounter:Float;
+
+ public function new(world:GameWorld)
+ {
+ super(world);
+
+ type = EntityType.ENEMY_SHIP;
+
+ collisionCategory = CollisionCategory.ENEMY;
+ collisionMask = CollisionCategory.PLAYER_BULLET | CollisionCategory.PLAYER;
+
+ shipType = Math.random() > 0.6 ? TESLA : BALOON;
+
+ if (shipType == TESLA)
+ {
+ createAsTesla();
+ }
+ else
+ {
+ createAsBalloon();
+ }
+
+ counter = 0;
+ smokeCounter = 0;
+
+ init();
+ }
+
+ override public function reset():Void
+ {
+ super.reset();
+
+ clearShapes();
+ rotation = 0;
+ speed.x = 0;
+ speed.y = 0;
+ counter = 0;
+ smokeCounter = 0;
+
+ collisionCategory = CollisionCategory.ENEMY;
+ collisionMask = CollisionCategory.PLAYER_BULLET | CollisionCategory.PLAYER;
+
+ shotDown = false;
+ unguidedProjectile = false;
+
+ shipType = Math.random() > 0.6 ? TESLA : BALOON;
+
+ if (shipType == TESLA)
+ {
+ createAsTesla();
+ }
+ else
+ {
+ createAsBalloon();
+ }
+
+ init();
+ }
+
+ override public function reactToCollision(collidingBody:PhysicalBody, selfShape:BaseShape, otherShape:BaseShape):Void
+ {
+ cast(collidingBody, GameEntity).recieveDamage(5);
+ if (shotDown)
+ {
+ if (Type.getClass(collidingBody) == Tile)
+ {
+ die();
+ }
+ }
+ }
+
+ public function die():Void
+ {
+ dead = true;
+ var exp:GameEntity = world.getReusableEntityByType(EntityType.EXPLOSION);
+ exp.position = position.clone();
+ world.addParticle(exp);
+
+ var debriesChance:Float = shipType == TESLA ? 0.8 : 0.6;
+ var maxNumber:Int = shipType == TESLA ? 6 : 2;
+ var minNumber:Int = shipType == TESLA ? 3 : 1;
+
+
+ while (Math.random() < debriesChance || minNumber > 0)
+ {
+ var debries:GameEntity = world.getReusableEntityByType(EntityType.DEBRIES);
+ debries.position.x = x;
+ debries.position.y = y;
+ debries.speed.x = (Math.random() * 10 - 5)*30;
+ debries.speed.y = (-Math.random() * 5 - 5)*30;
+ world.addParticle(debries);
+ minNumber--;
+ if (--maxNumber < 1)
+ {
+ break;
+ }
+ }
+
+ }
+
+ override public function update(dTime:Float):Void
+ {
+ super.update(dTime);
+ if (behaviour != null)
+ {
+ behaviour.update(dTime);
+ }
+ if (x < world.activeZoneStartMarker - 60)
+ {
+ dead = true;
+ }
+
+ if (!dead && shotDown)
+ {
+ if (smokeCounter > 0.125)
+ {
+ var smokeParticle:GameEntity = world.getReusableEntityByType(EntityType.SMOKE);
+ smokeParticle.position.x = position.x + 5;
+ smokeParticle.position.y = position.y - 5;
+ world.addParticle(smokeParticle);
+ smokeCounter = 0;
+ }
+ else
+ {
+ smokeCounter+=dTime;
+ }
+ }
+
+ }
+
+ public function shootAtPlayer():Void
+ {
+ var player:GameEntity = world.player;
+ var dx:Int = Std.int(player.x - x);
+ dx = Std.int(dx* 0.9);
+ var dy:Int = Std.int(player.y - y);
+ var angle:Float = Math.atan2(dy, dx);
+ var bullet:GameEntity = world.getReusableEntityByType(EntityType.ENEMY_BULLET);
+ bullet.position.x = x;
+ bullet.position.y = y;
+ bullet.speed.x = 360*Math.cos(angle);
+ bullet.speed.y = 360*Math.sin(angle);
+ world.addEnemyBullet(bullet);
+ }
+
+ public function shoot(angle:Float, speed:Float):Void
+ {
+ var bullet:GameEntity = world.getReusableEntityByType(EntityType.ENEMY_BULLET);
+ bullet.position.y = y;
+ bullet.speed.x = speed*Math.cos(angle);
+ bullet.speed.y = speed * Math.sin(angle);
+ if (shipType == TESLA)
+ {
+ bullet.frameRectNum = 0;
+ bullet.position.x = x - 26;
+ cast(bullet, EnemyBullet).bulletDamage = 15;
+ }
+ else
+ {
+ bullet.position.x = x;
+ bullet.frameRectNum = 1;
+ cast(bullet, EnemyBullet).bulletDamage = 30;
+ }
+ world.addEnemyBullet(bullet);
+ }
+
+ override public function recieveDamage(damageAmount:Int):Void
+ {
+ super.recieveDamage(damageAmount);
+ if (Type.getClass(behaviour) == BasicBehaviour)
+ {
+ cast(behaviour, BasicBehaviour).respondToDamage();
+ }
+ if (shipType == TESLA)
+ {
+ if (healthPoints < 0)
+ {
+ frameRectNum = 2;
+ } else if (healthPoints < 100)
+ {
+ frameRectNum = 1;
+ }
+ }
+ }
+
+ private function createAsBalloon():Void
+ {
+ graphicsAsset = GraphicsLibrary.getBaloon();
+ var circle:CircleShape= new CircleShape(-10,0,12);
+ circle.sensor = true;
+ addShape(circle);
+ healthPoints = 100;
+ speed.x = Std.int(Math.random() * -2 - 1) *10;
+ if (Math.random() > 0.5)
+ {
+ behaviour = new BaloonBehaviour(this);
+ } else
+ {
+ behaviour = new KamikazeBaloonBehaviour(this);
+ }
+ }
+
+ private function createAsTesla():Void
+ {
+ graphicsAsset = GraphicsLibrary.getTeslaFlyer();
+ var shape:Polygon = new Polygon();
+ shape.sensor = true;
+ shape.setAsBox(50, 12);
+ addShape(shape);
+ healthPoints = 200;
+ if (Math.random() > 0.7)
+ {
+ speed.x = Std.int(Math.random() * -4 - 4)*40;
+ behaviour = new TeslaBehaviourRam(this);
+ } else
+ {
+ speed.x = Std.int(Math.random() * -6 - 1)*40;
+ behaviour = new TeslaBehaviourFrontalAssault(this);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/EntityType.hx b/src/game/EntityType.hx
new file mode 100644
index 0000000..abc07d9
--- /dev/null
+++ b/src/game/EntityType.hx
@@ -0,0 +1,23 @@
+package game;
+
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+
+class EntityType
+{
+
+ static public inline var PLAYER:String = "player";
+ static public inline var TILE:String = "tile";
+ static public inline var PLAYER_BULLET:String = "playerBullet";
+ static public inline var ENEMY_BULLET:String = "enemyBullet";
+ static public inline var BULLET_HIT:String = "bulletHit";
+ static public inline var RAILGUN_TRAIL:String = "railgunTrail";
+ static public inline var ENEMY_SHIP:String = "enemyShip";
+ static public inline var DEBRIES:String = "debries";
+ static public inline var EXPLOSION:String = "explosion";
+ static public inline var SMOKE:String = "smoke";
+ static public inline var UNKNOWN:String = "unknown";
+
+}
\ No newline at end of file
diff --git a/src/game/Explosion.hx b/src/game/Explosion.hx
new file mode 100644
index 0000000..31ef8e0
--- /dev/null
+++ b/src/game/Explosion.hx
@@ -0,0 +1,42 @@
+package game;
+
+//import assets.GraphicsLibrary;
+import assets.GraphicsLibrary;
+import sphaeraGravita.shapes.CircleShape;
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class Explosion extends GameEntity
+{
+ private var counter:Float;
+
+ public function new(world:GameWorld)
+ {
+ super(world);
+ type = EntityType.EXPLOSION;
+ graphicsAsset = GraphicsLibrary.getExplosion1();
+ gridBound = true;
+ unguidedProjectile = true;
+ init();
+ counter = 0;
+ }
+
+ override public function reset():Void
+ {
+ super.reset();
+ counter = 0;
+ }
+
+ override public function update(dTime:Float):Void
+ {
+ super.update(dTime);
+ counter+=dTime;
+ frameRectNum = Std.int(counter*5*1.25);
+ if (counter >= 0.8)
+ {
+ dead = true;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/GameEntity.hx b/src/game/GameEntity.hx
new file mode 100644
index 0000000..c8be2a3
--- /dev/null
+++ b/src/game/GameEntity.hx
@@ -0,0 +1,52 @@
+package game;
+
+import assets.EntityGraphicsAsset;
+import sphaeraGravita.collision.PhysicalBody;
+import sphaeraGravita.shapes.BaseShape;
+/**
+ * ...
+ * @author Dimonte
+ */
+class GameEntity extends PhysicalBody
+{
+ public var world:GameWorld;
+ public var healthPoints:Int;
+ public var unguidedProjectile:Bool;
+ public var graphicsAsset:EntityGraphicsAsset;
+ public var frameRectNum:Int;
+ public var type:String;
+
+ public function new(world:GameWorld)
+ {
+ this.world = world;
+ type = EntityType.UNKNOWN;
+ super();
+ }
+
+ public function reset():Void
+ {
+ dead = false;
+ frameRectNum = 0;
+ }
+
+ public function destroy():Void
+ {
+ dead = true;
+ }
+
+ public function update(dTime:Float):Void
+ {
+
+ }
+
+ public function doDamage():Void
+ {
+
+ }
+
+ public function recieveDamage(damageAmount:Int):Void
+ {
+ healthPoints -= damageAmount;
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/GameEvent.hx b/src/game/GameEvent.hx
new file mode 100644
index 0000000..1a291c3
--- /dev/null
+++ b/src/game/GameEvent.hx
@@ -0,0 +1,23 @@
+package game;
+import flash.events.Event;
+
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+
+class GameEvent extends Event
+{
+ static public inline var GAME_OVER:String = "gameOver";
+
+ public function new(type:String, bubbles:Bool = false, cancelable:Bool = false)
+ {
+ super(type, bubbles, cancelable);
+ }
+
+ override public function clone():Event
+ {
+ return new GameEvent(type, bubbles, cancelable);
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/GameStage.hx b/src/game/GameStage.hx
new file mode 100644
index 0000000..2fec3b3
--- /dev/null
+++ b/src/game/GameStage.hx
@@ -0,0 +1,143 @@
+package game;
+
+import com.sphaeraobscura.keyboard.KeyKeeper;
+import flash.events.EventDispatcher;
+//import utils.logger.Logger;
+/**
+ * ...
+ * @author ...
+ */
+class GameStage extends EventDispatcher
+{
+ /**
+ * Speed of moving through level in pixels/second.
+ */
+ static private inline var ACTIVE_ZONE_SHIFT:Float= 60;
+
+ public var gameWorld:GameWorld;
+ public var player:PlayerShip;
+ public var playerController:PlayerController;
+ private var loadedLevel:Level;
+ private var gameOver:Bool;
+ private var activeZoneWidth:Int;
+ private var activeZoneHeight:Int;
+
+
+
+ public function new(activeZoneWidth:Int, activeZoneHeight:Int)
+ {
+ super();
+ this.activeZoneWidth = activeZoneWidth;
+ this.activeZoneHeight = activeZoneHeight;
+ gameWorld = new GameWorld(activeZoneWidth, activeZoneHeight);
+ }
+
+ public function initializeStage():Void
+ {
+ gameWorld.clear();
+ player = new PlayerShip(gameWorld);
+ player.position.x = 60;
+ player.position.y = 100;
+ playerController = new PlayerController(player);
+ gameWorld.addActiveEntity(player);
+ gameWorld.player = player;
+
+ loadLevel(new Level(activeZoneWidth, activeZoneHeight));
+
+ gameOver = false;
+ }
+
+ public function loadLevel(level:Level):Void
+ {
+ loadedLevel = level;
+ //Logger.log("level.tiles.length : " + level.tiles.length);
+
+ level.tiles.sort(sortEntityOnX);
+
+ level.enemies.sort(sortEntityOnX);
+ }
+
+ private function sortEntityOnX(a:LevelObjectTemplate, b:LevelObjectTemplate):Int
+ {
+ if (a.position.x < b.position.x)
+ {
+ return 1;
+ }
+ if (a.position.x > b.position.x)
+ {
+ return -1;
+ }
+ if (a.position.x == b.position.x)
+ {
+ return 0;
+ }
+ return 0;
+ }
+
+ private function spawnTiles():Void
+ {
+ while (loadedLevel.tiles.length > 0)
+ {
+ var tileTemplate:LevelObjectTemplate = loadedLevel.tiles[loadedLevel.tiles.length-1];
+ if (tileTemplate.position.x <= gameWorld.activeZoneStartMarker + activeZoneWidth + 60)
+ {
+ var tile:Tile = cast(gameWorld.getReusableEntityByType(EntityType.TILE), Tile);
+ tile.position = tileTemplate.position;
+ tile.createFromTemplate(cast(tileTemplate, TileTemplate).tileTemplate);
+ gameWorld.addTile(tile);
+ loadedLevel.tiles.pop();
+ } else
+ {
+ break;
+ }
+ }
+ }
+
+ private function spawnEnemies():Void
+ {
+ while (loadedLevel.enemies.length > 0)
+ {
+ var enemyTemplate:LevelObjectTemplate = loadedLevel.enemies[loadedLevel.enemies.length-1];
+ if (enemyTemplate.position.x <= gameWorld.activeZoneStartMarker + activeZoneWidth + 60)
+ {
+ var enemy:GameEntity = gameWorld.getReusableEntityByType(EntityType.ENEMY_SHIP);
+ enemy.x = enemyTemplate.position.x;
+ enemy.y = enemyTemplate.position.y;
+ gameWorld.addEnemy(enemy);
+ loadedLevel.enemies.pop();
+ } else
+ {
+ break;
+ }
+ }
+ }
+
+ public function update(dTime:Float):Void
+ {
+ if (!player.dead)
+ {
+
+ gameWorld.activeZoneStartMarker += ACTIVE_ZONE_SHIFT*dTime;
+ player.x += 60*dTime;
+
+ playerController.update(dTime);
+
+ spawnEnemies();
+
+ spawnTiles();
+ }
+ else
+ {
+ if (!gameOver)
+ {
+ gameOver = true;
+ dispatchEvent(new GameEvent(GameEvent.GAME_OVER));
+ }
+ }
+
+
+
+ gameWorld.update(dTime);
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/GameWorld.hx b/src/game/GameWorld.hx
new file mode 100644
index 0000000..8e40d55
--- /dev/null
+++ b/src/game/GameWorld.hx
@@ -0,0 +1,365 @@
+package game;
+
+import dataStructures.DLL;
+import dataStructures.DLLNode;
+import flash.errors.Error;
+import game.CollisionCategory;
+import game.GameEntity;
+import haxe.ds.GenericStack;
+import haxe.ds.StringMap;
+import sphaeraGravita.collision.CollisionEngine;
+import sphaeraGravita.spacePartitioning.GridCell;
+import sphaeraGravita.spacePartitioning.UniformGrid;
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class GameWorld
+{
+ public var activeZoneStartMarker:Float;
+
+ public var collisionEngine:CollisionEngine;
+
+ public var grid:UniformGrid;
+
+ public var player:PlayerShip;
+ public var players:DLL;
+ public var tiles:DLL;
+ //public var stationaryObjects:DLL;
+ public var particles:DLL;
+ public var enemies:DLL;
+ public var playerBullets:DLL;
+ public var enemyBullets:DLL;
+
+ public var score:Int;
+
+ private var reuseLists:StringMap>;
+
+ private var activeZoneWidth:Int;
+ private var activeZoneHeight:Int;
+
+ public function new(activeZoneWidth:Int, activeZoneHeight:Int)
+ {
+ this.activeZoneWidth = activeZoneWidth;
+ this.activeZoneHeight = activeZoneHeight;
+
+ activeZoneStartMarker = 0;
+ reuseLists = new StringMap();
+ collisionEngine = new CollisionEngine();
+ players = new DLL();
+ playerBullets = new DLL();
+ enemyBullets = new DLL();
+ tiles = new DLL();
+ enemies = new DLL();
+ particles = new DLL();
+ grid = new UniformGrid();
+ grid.initialize(Level.LEVEL_WIDTH, Math.ceil(activeZoneHeight/40), 4);
+ }
+
+ public function clear():Void
+ {
+ player = null;
+ players.clear();
+ tiles.clear();
+ //stationaryObjects.clear();
+ particles.clear();
+ enemies.clear();
+ playerBullets.clear();
+ enemyBullets.clear();
+
+ grid.initialize(Level.LEVEL_WIDTH, Math.ceil(activeZoneHeight/40), 4);
+ score = 0;
+ activeZoneStartMarker = 0;
+ }
+
+ private function initializeFixedEntities():Void
+ {
+
+ }
+
+ public function addActiveEntity(gameEntity:GameEntity):Void
+ {
+ players.append(gameEntity);
+ }
+
+ public function addEnemy(enemy:GameEntity):Void
+ {
+ enemies.append(enemy);
+ }
+
+ public function addPlayerBullet(gameEntity:GameEntity):Void
+ {
+ playerBullets.append(gameEntity);
+ }
+
+ public function addEnemyBullet(gameEntity:GameEntity):Void
+ {
+ enemyBullets.append(gameEntity);
+ }
+
+ public function addFixedEntiry(gameEntity:GameEntity):Void
+ {
+ tiles.append(gameEntity);
+ gameEntity.updateWorldCache();
+ }
+
+ public function addTile(tile:Tile):Void
+ {
+ tiles.append(tile);
+ tile.updateWorldCache();
+ grid.placeTile(tile);
+ }
+
+ public function addParticle(particle:GameEntity):Void
+ {
+ particle.updateWorldCache();
+ grid.placeActiveObject(particle);
+ particles.append(particle);
+ }
+
+ public function update(dTime:Float):Void
+ {
+ grid.clean();
+
+ //trace(playerBullets.length);
+
+ updatePositionsInList(players, dTime);
+ if (player.worldAABB.lowerBound.x < activeZoneStartMarker)
+ {
+ player.position.x += activeZoneStartMarker - player.worldAABB.lowerBound.x;
+ player.updateWorldCache();
+ }
+
+ if (player.worldAABB.upperBound.x > activeZoneStartMarker+activeZoneWidth)
+ {
+ player.position.x += activeZoneStartMarker + activeZoneWidth - player.worldAABB.upperBound.x;
+ player.updateWorldCache();
+ }
+
+ if (player.worldAABB.lowerBound.y < 0)
+ {
+ player.position.y += 0 - player.worldAABB.lowerBound.y;
+ player.updateWorldCache();
+ }
+
+ if (player.worldAABB.upperBound.y > activeZoneHeight && player.healthPoints > 0)
+ {
+ player.position.y += activeZoneHeight - player.worldAABB.upperBound.y;
+ player.updateWorldCache();
+ }
+
+ updateTiles();
+
+ updatePositionsInList(playerBullets, dTime);
+ updatePositionsInList(enemyBullets, dTime);
+ updatePositionsInList(enemies, dTime);
+ updatePositionsInList(particles, dTime);
+
+ collideObjectWithGrid(player);
+ collideListWithList(players, enemies);
+ collideListWithList(players, particles);
+ collideListWithGrid(enemies, grid);
+ collideListWithGrid(playerBullets, grid);
+ collideListWithGrid(enemyBullets, grid);
+ collideListWithGrid(particles, grid);
+
+ updateLogicInList(players, dTime);
+ updateLogicInList(playerBullets, dTime);
+ updateLogicInList(enemies, dTime);
+ updateLogicInList(particles, dTime);
+ }
+
+ private function updateTiles()
+ {
+ var activeBodyNode:DLLNode = tiles._head;
+ var activeBody:GameEntity;
+ while (activeBodyNode != null)
+ {
+ activeBody = cast(activeBodyNode.val, GameEntity);
+ if (activeBody.worldAABB.upperBound.x < activeZoneStartMarker)
+ {
+ tiles.remove(activeBodyNode);
+ placeEntityForReuse(activeBody);
+ }
+
+ activeBodyNode = activeBodyNode.next;
+ }
+ }
+
+ public function updatePositionsInList(list:DLL, dTime:Float):Void
+ {
+ var activeBodyNode:DLLNode = list._head;
+ var activeBody:GameEntity;
+ while (activeBodyNode != null)
+ {
+ activeBody = cast(activeBodyNode.val, GameEntity);
+ if (activeBody.dead)
+ {
+ list.remove(activeBodyNode); //TODO transfer to logic update?
+ placeEntityForReuse(activeBody);
+ } else {
+ activeBody.position.x += activeBody.speed.x*dTime;
+ activeBody.position.y += activeBody.speed.y*dTime;
+ activeBody.updateWorldCache();
+ if (activeBody.gridBound)
+ {
+ grid.placeActiveObject(activeBody);
+ }
+ if (activeBody.unguidedProjectile)
+ {
+ if (!activeBody.inBounds(activeZoneStartMarker, 0, activeZoneWidth, activeZoneHeight))
+ {
+ activeBody.dead = true;
+ }
+ }
+ }
+
+ activeBodyNode = activeBodyNode.next;
+ }
+ }
+
+ public function placeEntityForReuse(activeBody:GameEntity)
+ {
+ if (activeBody.type == EntityType.UNKNOWN)
+ {
+ throw new Error("Unknown type of reusable asset");
+ return;
+ }
+ var reuseList:GenericStack = reuseLists.get(activeBody.type);
+ if (reuseList == null)
+ {
+ reuseList = new GenericStack();
+ reuseLists.set(activeBody.type, reuseList);
+ }
+ reuseList.add(activeBody);
+ }
+
+ public function getReusableEntityByType(type:String):GameEntity
+ {
+ var newEntity:GameEntity = null;
+
+ var reuseList:GenericStack = reuseLists.get(type);
+ if (reuseList != null)
+ {
+ if (reuseList.head != null)
+ {
+ newEntity = reuseList.pop();
+ newEntity.reset();
+ return newEntity;
+ }
+ }
+
+ switch (type)
+ {
+ case EntityType.BULLET_HIT:
+ newEntity = new BulletHit(this);
+ case EntityType.ENEMY_BULLET:
+ newEntity = new EnemyBullet(this);
+ case EntityType.PLAYER:
+ newEntity = new PlayerShip(this);
+ case EntityType.PLAYER_BULLET:
+ newEntity = new Bullet(this);
+ case EntityType.RAILGUN_TRAIL:
+ newEntity = new RailgunTrail(this);
+ case EntityType.ENEMY_SHIP:
+ newEntity = new EnemyShip(this);
+ case EntityType.DEBRIES:
+ newEntity = new Debries(this);
+ case EntityType.EXPLOSION:
+ newEntity = new Explosion(this);
+ case EntityType.TILE:
+ newEntity = new Tile(this);
+ case EntityType.SMOKE:
+ newEntity = new SmokeParticle(this);
+ default:
+ newEntity = new GameEntity(this);
+ }
+
+ return newEntity;
+ }
+
+ public function updateLogicInList(list:DLL, dTime:Float):Void
+ {
+ var activeBodyNode:DLLNode = list._head;
+ var activeBody:GameEntity;
+ while (activeBodyNode != null)
+ {
+
+ activeBody = cast(activeBodyNode.val, GameEntity);
+ activeBodyNode = activeBodyNode.next;
+ activeBody.update(dTime);
+
+ }
+ }
+
+ public function collideListWithList(listOne:DLL, listTwo:DLL):Void
+ {
+ var listOneNode:DLLNode = listOne._head;
+ var listOneEntity:GameEntity;
+ while (listOneNode != null)
+ {
+ listOneEntity = cast(listOneNode.val, GameEntity);
+ var listTwoNode:DLLNode = listTwo._head;
+ var listTwoEntity:GameEntity;
+ while (listTwoNode != null)
+ {
+ listTwoEntity = cast(listTwoNode.val, GameEntity);
+ collisionEngine.collideBodies(listOneEntity, listTwoEntity);
+ listTwoNode = listTwoNode.next;
+ }
+ listOneNode = listOneNode.next;
+ }
+ }
+
+ public function collideObjectWithGrid(object:GameEntity):Void
+ {
+ if (object.collisionCategory == CollisionCategory.IGNORE)
+ return;
+
+ var coveredCells:Array;
+ if (object.gridBound)
+ {
+ coveredCells = object.overlappingCells;
+ } else
+ {
+ coveredCells = grid.getCellsBetweenPoints(object.worldAABB.lowerBound, object.worldAABB.upperBound);
+ }
+ var cellListNode:DLLNode;
+ var cellObject:GameEntity;
+ //trace("coveredCells.length: " + coveredCells.length);
+ for (i in 0...coveredCells.length)
+ {
+ cellListNode = coveredCells[i].fixedObjectList._head;
+ while (cellListNode != null)
+ {
+ cellObject = cast(cellListNode.val, GameEntity);
+
+ if (cellObject != object)
+ collisionEngine.collideBodies(object, cellObject);
+
+ cellListNode = cellListNode.next;
+ }
+ cellListNode = coveredCells[i].activeObjectList._head;
+ while (cellListNode != null)
+ {
+ cellObject = cast(cellListNode.val, GameEntity);
+
+ if (cellObject != object)
+ collisionEngine.collideBodies(object, cellObject);
+
+ cellListNode = cellListNode.next;
+ }
+ }
+ }
+
+ public function collideListWithGrid(list:DLL, grid:UniformGrid):Void
+ {
+ var listNode:DLLNode = list._head;
+ while (listNode != null)
+ {
+ collideObjectWithGrid(cast(listNode.val, GameEntity));
+ listNode = listNode.next;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/Level.hx b/src/game/Level.hx
new file mode 100644
index 0000000..7f5ba81
--- /dev/null
+++ b/src/game/Level.hx
@@ -0,0 +1,288 @@
+package game;
+
+import game.TileTemplate;
+import haxe.ds.IntMap.IntMap;
+
+/**
+ * ...
+ * @author Dimonte
+ */
+class Level
+{
+
+ static public inline var LEVEL_WIDTH:Int = 600;
+ public var tiles:Array;
+ public var enemies:Array;
+ private var surroundingTiles:Array;
+ private var levelHeight:Int;
+ private var activeZoneWidth:Int;
+ private var activeZoneHeight:Int;
+
+ static public var templatePriority:Array =
+ {
+ [TilePositionTemplate.middle, TilePositionTemplate.slopeUp, TilePositionTemplate.slopeDown, TilePositionTemplate.top ];
+
+ }
+
+ public function new(activeZoneWidth:Int, activeZoneHeight:Int)
+ {
+ this.activeZoneWidth = activeZoneWidth;
+ this.activeZoneHeight = activeZoneHeight;
+ this.levelHeight = Math.ceil(activeZoneHeight/40);
+ surroundingTiles = new Array();
+ tiles = new Array();
+ enemies = new Array();
+ var normalHeight:Int = 2;
+ var previousHeight:Int = normalHeight;
+ var height:Int = previousHeight;
+ var heightChangeSpeed:Int = 0;
+ var tileGrid:TileGrid = new TileGrid(LEVEL_WIDTH, levelHeight);
+
+ var tileTemplate:TileTemplate;
+ for (i in 0...LEVEL_WIDTH)
+ {
+ var heightChangeSpeedChange:Int = Std.int(Math.random() * 2) + Std.int(Math.random() * 2) - 1;
+ if (height > normalHeight && heightChangeSpeed > 0) {
+ heightChangeSpeedChange += Math.round((normalHeight - height) / 1);
+ }
+ if (height < normalHeight && heightChangeSpeed < 0) {
+ heightChangeSpeedChange += Math.round((normalHeight - height) / 1);
+ }
+ heightChangeSpeed += heightChangeSpeedChange;
+ height += heightChangeSpeed;
+
+ for (j in 0...height)
+ {
+ tileTemplate = new TileTemplate();
+ tileTemplate.tileGridX = i;
+ tileTemplate.tileGridY = levelHeight - 1 - j;
+ tileTemplate.position.x = i * 40 + 20;
+ tileTemplate.position.y = Std.int(levelHeight - 1 - j) * 40 + 20;
+ tiles.push(tileTemplate);
+ tileGrid.addTileAt(i, levelHeight - 1 - j, tileTemplate);
+ }
+ previousHeight = height;
+ }
+
+ for (i in 0...tiles.length)
+ {
+ tileTemplate = cast(tiles[i], TileTemplate);
+ findTemplateForTile(tileTemplate, tileGrid);
+ }
+
+ for (i in 0...160)
+ {
+
+ var diffMod:Float = (160 - i) / 160 - 0.4;
+ var minShips:Int = Std.int(i / 40) +1;
+ var shipsAdded:Int = 0;
+
+ while (Math.random() > diffMod || shipsAdded < minShips)
+ {
+ diffMod += 0.05;
+ var enemyShipTemplate:LevelObjectTemplate = new LevelObjectTemplate();
+ enemyShipTemplate.position.x = i * 90 + activeZoneWidth + Math.random()*90;
+ enemyShipTemplate.position.y = Math.random() * activeZoneHeight/2 + 40;
+ enemies.push(enemyShipTemplate);
+ shipsAdded++;
+ }
+ }
+
+ tileGrid = null;
+ }
+
+ private function findTemplateForTile(tileTemplate:TileTemplate, tileGrid:TileGrid):Void
+ {
+ //To match templates, reading in column/row
+ for (j in 0...3)
+ {
+ for (i in 0...3)
+ {
+ surroundingTiles[i+j*3] = tileGrid.isTileAt(i + tileTemplate.tileGridX - 1, j + tileTemplate.tileGridY - 1);
+ }
+ }
+
+ var matchFound:Bool = false;
+ var tilePositionTemplate:TilePositionTemplate = null;
+ var positionTemplate:Array;
+ for (i in 0...templatePriority.length)
+ {
+ tilePositionTemplate = templatePriority[i];
+ positionTemplate = tilePositionTemplate.template;
+ matchFound = true;
+ for (j in 0...positionTemplate.length)
+ {
+ if (positionTemplate[j] == -1)
+ {
+ continue;
+ }
+ if (positionTemplate[j] == 0)
+ {
+ if (surroundingTiles[j])
+ {
+ matchFound = false;
+ break;
+ }
+ }
+ if (positionTemplate[j] == 1)
+ {
+ if (!surroundingTiles[j])
+ {
+ matchFound = false;
+ break;
+ }
+ }
+ }
+ if (matchFound)
+ {
+ break;
+ }
+ }
+
+ if (!matchFound)
+ {
+ tilePositionTemplate = TilePositionTemplate.top;
+ }
+
+ tileTemplate.tileTemplate = tilePositionTemplate.code;
+
+ }
+
+}
+
+class TileGrid
+{
+ private var standInTile:TileTemplate;
+ private var tileHash:IntMap>;
+ private var width:Int;
+ private var height:Int;
+
+ public function new(width:Int, height:Int)
+ {
+ standInTile = new TileTemplate();
+ this.width = width;
+ this.height = height;
+ tileHash = new IntMap();
+ var tileColumnHash:IntMap;
+ for (i in 0...width)
+ {
+ tileColumnHash = new IntMap();
+ tileHash.set(i, tileColumnHash);
+ }
+ }
+
+ public function addTileAt(x:Int, y:Int, tileTemplate:TileTemplate):Void
+ {
+ tileHash.get(x).set(y, tileTemplate);
+ }
+
+ public function getTileAt(x:Int, y:Int):Null
+ {
+ if (x < 0)
+ {
+ return null;
+ }
+ if (x >= width)
+ {
+ return null;
+ }
+ if (y < 0)
+ {
+ return null;
+ }
+ if (y >= height)
+ {
+ return standInTile;
+ }
+ return tileHash.get(x).get(y);
+ }
+
+ public function isTileAt(x:Int, y:Int):Bool
+ {
+ if (x < 0)
+ {
+ return false;
+ }
+ if (x >= width)
+ {
+ return false;
+ }
+ if (y < 0)
+ {
+ return false;
+ }
+ if (y >= height)
+ {
+ return true;
+ }
+ return tileHash.get(x).get(y) != null;
+ }
+}
+
+class TilePositionTemplate
+{
+
+ static public var slopeUp:TilePositionTemplate =
+ {
+ var tilePosTemp:TilePositionTemplate = new TilePositionTemplate();
+ tilePosTemp.template =
+ [ -1, 0, -1,
+ 0, 1, 1,
+ -1, 1, 1]
+ ;
+
+ /*tilePosTemp.template =
+ [ -1, -1, -1,
+ -1, -1, -1,
+ -1, -1, -1]
+ ;*/
+
+ tilePosTemp.code = Tile.SLOPE_UP;
+ tilePosTemp;
+ }
+
+ static public var slopeDown:TilePositionTemplate =
+ {
+ var tilePosTemp:TilePositionTemplate = new TilePositionTemplate();
+ tilePosTemp.template =
+ [ -1, 0, -1,
+ 1, 1, 0,
+ 1, 1, -1]
+ ;
+ tilePosTemp.code = Tile.SLOPE_DOWN;
+ tilePosTemp;
+ }
+
+ static public var middle:TilePositionTemplate =
+ {
+ var tilePosTemp:TilePositionTemplate = new TilePositionTemplate();
+ tilePosTemp.template =
+ [ -1, 1, -1,
+ -1, 1, -1,
+ -1, 1, -1]
+ ;
+ tilePosTemp.code = Tile.MIDDLE;
+ tilePosTemp;
+ }
+
+ static public var top:TilePositionTemplate =
+ {
+ var tilePosTemp:TilePositionTemplate = new TilePositionTemplate();
+ tilePosTemp.template =
+ [ -1, 0, -1,
+ -1, 1, -1,
+ -1, 1, -1]
+ ;
+ tilePosTemp.code = Tile.TOP;
+ tilePosTemp;
+ }
+
+
+ public var template:Array;
+ public var code:String;
+
+ public function new()
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/src/game/LevelObjectTemplate.hx b/src/game/LevelObjectTemplate.hx
new file mode 100644
index 0000000..3103f1b
--- /dev/null
+++ b/src/game/LevelObjectTemplate.hx
@@ -0,0 +1,19 @@
+package game;
+import sphaeraGravita.math.Vector2D;
+
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+
+class LevelObjectTemplate
+{
+
+ public var position:Vector2D;
+
+ public function new()
+ {
+ position = new Vector2D();
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/PlayerController.hx b/src/game/PlayerController.hx
new file mode 100644
index 0000000..ecf9eca
--- /dev/null
+++ b/src/game/PlayerController.hx
@@ -0,0 +1,87 @@
+package game;
+import game.PlayerShip;
+
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+
+class PlayerController
+{
+ private var horizontalAccelerationMax:Float;
+ private var verticalAccelerationMax:Float;
+
+ private var player:PlayerShip;
+
+ private var horizontalAcceleration:Float;
+ private var verticalAcceleration:Float;
+ private var shootOnUpdate:Bool;
+
+ public function new(player:PlayerShip)
+ {
+ this.player = player;
+ horizontalAccelerationMax = 3000;
+ verticalAccelerationMax = 3000;
+ horizontalAcceleration = 0;
+ verticalAcceleration = 0;
+ }
+
+ public function accelerateRight(?magnitude:Float = 1.0):Void
+ {
+ horizontalAcceleration += magnitude;
+ }
+
+ public function accelerateLeft(?magnitude:Float = 1.0):Void
+ {
+ horizontalAcceleration -= magnitude;
+ }
+
+ public function accelrateDown(?magnitude:Float = 1.0):Void
+ {
+ verticalAcceleration += magnitude;
+ }
+
+ public function accelrateUp(?magnitude:Float = 1.0):Void
+ {
+ verticalAcceleration -= magnitude;
+ }
+
+ public function setHorizontalAcceleration(magnitude:Float):Void
+ {
+ horizontalAcceleration = magnitude;
+ }
+
+ public function setVerticalAcceleration(magnitude:Float):Void
+ {
+ verticalAcceleration = magnitude;
+ }
+
+ public function update(dTime:Float):Void
+ {
+ if (player == null)
+ {
+ return;
+ }
+ if (player.dead || player.healthPoints < 0)
+ {
+ return;
+ }
+ horizontalAcceleration = Math.max(Math.min(horizontalAcceleration, 1), -1);
+ verticalAcceleration = Math.max(Math.min(verticalAcceleration, 1), -1);
+ player.speed.x += horizontalAcceleration * horizontalAccelerationMax * dTime;
+ player.speed.y += verticalAcceleration * verticalAccelerationMax * dTime;
+ if (shootOnUpdate)
+ {
+ player.shoot();
+ }
+ horizontalAcceleration = 0;
+ verticalAcceleration = 0;
+ shootOnUpdate = false;
+ }
+
+ public function shoot():Void
+ {
+ shootOnUpdate = true;
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/PlayerShip.hx b/src/game/PlayerShip.hx
new file mode 100644
index 0000000..68c2c25
--- /dev/null
+++ b/src/game/PlayerShip.hx
@@ -0,0 +1,176 @@
+package game;
+import assets.EntityGraphicsAsset;
+import assets.GraphicsLibrary;
+import sphaeraGravita.collision.PhysicalBody;
+import sphaeraGravita.math.Vector2D;
+import sphaeraGravita.shapes.BaseShape;
+import sphaeraGravita.shapes.CircleShape;
+import sphaeraGravita.shapes.Polygon;
+
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class PlayerShip extends GameEntity
+{
+ private var reload:Int;
+ private var bulletAngle:Float;
+ private var smokeCounter:Float;
+ private var timePassedSinceLastSpeedUpdate:Float;
+ private var reloadTime:Float;
+
+ public function new(world:GameWorld)
+ {
+ super(world);
+ type = EntityType.PLAYER;
+
+ reloadTime = 0.02;
+ bulletAngle = 0;
+ smokeCounter = 0;
+ timePassedSinceLastSpeedUpdate = 0;
+
+ collisionCategory = CollisionCategory.PLAYER;
+ collisionMask = CollisionCategory.ENEMY | CollisionCategory.TILE | CollisionCategory.ENEMY_BULLET | CollisionCategory.PARTICLE;
+ graphicsAsset = GraphicsLibrary.getPlayerShip();
+
+ bounceFactor = 2;
+
+ var poly:Polygon = new Polygon();
+ poly.setPoly([new Vector2D( -55, 0), new Vector2D( -55, -10), new Vector2D(0, -15), new Vector2D(50, -10), new Vector2D(50, 10), new Vector2D(20, 22), new Vector2D(0, 22)]);
+ addShape(poly);
+ var circle:CircleShape = new CircleShape(20, 0, 11);
+ addShape(circle);
+ init();
+
+ healthPoints = 800;
+ }
+
+ public function accelerateForward():Void
+ {
+
+ }
+
+ public function accelerateBackwards():Void
+ {
+
+ }
+
+ public function accelerateUp():Void
+ {
+
+ }
+
+ public function accelerateDown():Void
+ {
+
+ }
+
+ override public function update(dTime:Float):Void
+ {
+
+ //healthPoints -= 10;
+
+ if (healthPoints <= 0)
+ {
+ unguidedProjectile = true;
+ speed.y += 900*dTime;
+ }
+
+ if (reloadTime > 0)
+ {
+ reloadTime-= dTime;
+ }
+
+ timePassedSinceLastSpeedUpdate += dTime;
+ while (timePassedSinceLastSpeedUpdate > 0.02)
+ {
+ speed.multiply(0.8);
+ timePassedSinceLastSpeedUpdate -= 0.02;
+ }
+
+ if (!dead && healthPoints <= 0)
+ {
+ if (smokeCounter >= 0.05)
+ {
+ var smokeParticle:GameEntity = world.getReusableEntityByType(EntityType.SMOKE);
+ smokeParticle.position.x = position.x - 20 + Math.random()*50;
+ smokeParticle.position.y = position.y - 10 + Math.random()*5;
+ world.addParticle(smokeParticle);
+ smokeCounter = 0;
+ }
+ else
+ {
+ smokeCounter+=dTime;
+ }
+ }
+ }
+
+ override public function reactToCollision(collidingBody:PhysicalBody, selfShape:BaseShape, otherShape:BaseShape):Void
+ {
+ super.reactToCollision(collidingBody, selfShape, otherShape);
+ cast(collidingBody, GameEntity).recieveDamage(10);
+ if (Type.getClass(collidingBody) == Tile)
+ {
+ if (healthPoints <= 0 )
+ {
+ dead = true;
+ var exp:GameEntity = world.getReusableEntityByType(EntityType.EXPLOSION);
+ exp.position = position.clone();
+ world.addParticle(exp);
+ while (Math.random() > 0.6)
+ {
+ var debries:GameEntity = world.getReusableEntityByType(EntityType.DEBRIES);
+ debries.position.x = x;
+ debries.position.y = y;
+ debries.speed.x = Math.random() * 10 - 5;
+ debries.speed.y = -Math.random() * 10;
+ world.addParticle(debries);
+ }
+ }
+ }
+ }
+
+ override public function recieveDamage(damageAmount:Int):Void
+ {
+ super.recieveDamage(damageAmount);
+ }
+
+ public function shoot():Void
+ {
+ if (healthPoints <= 0)
+ {
+ return;
+ }
+ if (reloadTime > 0)
+ {
+ return;
+ }
+ reloadTime = 0.02;
+ if (reload > 0)
+ {
+ reload--;
+ } else
+ {
+ reload = 1;
+ }
+
+ bulletAngle += Math.PI / 34;
+
+ var i:Int = 4;
+ while (i-- > 0)
+ {
+ if (i % 2 == reload)
+ {
+ continue;
+ }
+ var bullet:GameEntity = world.getReusableEntityByType(EntityType.PLAYER_BULLET);
+ bullet.position.x = this.position.x + 30;
+ bullet.position.y = this.position.y;
+ bullet.speed.x = 450;
+ bullet.speed.y = Math.sin((bulletAngle + i)*(i + 1))*60;
+ world.addPlayerBullet(bullet);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/RailgunTrail.hx b/src/game/RailgunTrail.hx
new file mode 100644
index 0000000..09e98ce
--- /dev/null
+++ b/src/game/RailgunTrail.hx
@@ -0,0 +1,50 @@
+package game;
+import assets.GraphicsLibrary;
+
+//import assets.GraphicsLibrary;
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class RailgunTrail extends GameEntity
+{
+ private var counter:Float;
+ private var timePassedSinceLastUpdate:Float;
+
+ public function new(world:GameWorld)
+ {
+ super(world);
+ type = EntityType.RAILGUN_TRAIL;
+ collisionCategory = CollisionCategory.IGNORE;
+ counter = 0;
+ graphicsAsset = GraphicsLibrary.getRailgunTrail();
+ gridBound = true;
+ unguidedProjectile = true;
+ timePassedSinceLastUpdate = 0;
+ init();
+ }
+
+ override public function reset():Void
+ {
+ super.reset();
+ counter = 0;
+ timePassedSinceLastUpdate = 0;
+ }
+
+ override public function update(dTime:Float):Void
+ {
+ super.update(dTime);
+ timePassedSinceLastUpdate += dTime;
+ while(timePassedSinceLastUpdate > 0.02)
+ {
+ speed.multiply(0.8);
+ timePassedSinceLastUpdate -= 0.02;
+ }
+ counter+=dTime;
+ if (counter > 0.4)
+ {
+ dead = true;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/SmokeParticle.hx b/src/game/SmokeParticle.hx
new file mode 100644
index 0000000..3821ed7
--- /dev/null
+++ b/src/game/SmokeParticle.hx
@@ -0,0 +1,42 @@
+package game;
+import assets.GraphicsLibrary;
+
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+
+class SmokeParticle extends GameEntity
+{
+ private var counter:Float;
+
+ public function new(world:GameWorld)
+ {
+ super(world);
+ counter = 0;
+ type = EntityType.SMOKE;
+ graphicsAsset = GraphicsLibrary.getSmoke();
+ gridBound = true;
+ unguidedProjectile = true;
+ speed.y = -1;
+ init();
+ }
+
+ override public function reset():Void
+ {
+ super.reset();
+ counter = 0;
+ }
+
+ override public function update(dTime:Float):Void
+ {
+ super.update(dTime);
+ counter+=dTime;
+ frameRectNum = Std.int(counter * 5);
+ if (counter >= 1)
+ {
+ dead = true;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/Tile.hx b/src/game/Tile.hx
new file mode 100644
index 0000000..db8a1de
--- /dev/null
+++ b/src/game/Tile.hx
@@ -0,0 +1,63 @@
+package game;
+
+import assets.GraphicsLibrary;
+import sphaeraGravita.collision.PhysicalBody;
+import sphaeraGravita.math.Vector2D;
+import sphaeraGravita.shapes.BaseShape;
+import sphaeraGravita.shapes.Polygon;
+
+/**
+ * ...
+ * @author Dimonte
+ */
+class Tile extends GameEntity
+{
+ public static inline var MIDDLE:String = "middle";
+ public static inline var TOP:String = "top";
+ public static inline var SLOPE_UP:String = "slopeUp";
+ public static inline var SLOPE_DOWN:String = "slopeDown";
+
+ public var template:String;
+
+ public function new(world:GameWorld)
+ {
+ super(world);
+ type = EntityType.TILE;
+ collisionCategory = CollisionCategory.TILE;
+ graphicsAsset = GraphicsLibrary.getTiles();
+ }
+
+ public function createFromTemplate(template:String):Void
+ {
+ clearShapes();
+ var shape:Polygon;
+ shape = new Polygon();
+ this.template = template;
+ switch (template)
+ {
+ case MIDDLE:
+ shape.setAsBox(20, 20);
+ frameRectNum = Math.random() > 0.2 ? graphicsAsset.getFrameByAssetName("assets/tiles/middle.png") : graphicsAsset.getFrameByAssetName("assets/tiles/middle2.png");
+ case SLOPE_UP:
+ shape.setPoly([new Vector2D( -20, 20), new Vector2D( 20, -20), new Vector2D( 20, 20)]);
+ frameRectNum = 2;
+ case SLOPE_DOWN:
+ shape.setPoly([new Vector2D( -20, -20), new Vector2D( 20, 20), new Vector2D( -20, 20)]);
+ frameRectNum = 3;
+ case TOP:
+ shape.setAsBox(20, 20);
+ frameRectNum = Math.random() > 0.2 ? graphicsAsset.getFrameByAssetName("assets/tiles/top2.png") : graphicsAsset.getFrameByAssetName("assets/tiles/top.png");
+ default:
+ shape.setAsBox(20, 20);
+ }
+ addShape(shape);
+ init();
+ }
+
+ override public function reactToCollision(collidingBody:PhysicalBody, selfShape:BaseShape, otherShape:BaseShape):Void
+ {
+ super.reactToCollision(collidingBody, selfShape, otherShape);
+ cast(collidingBody, GameEntity).recieveDamage(10);
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/TileTemplate.hx b/src/game/TileTemplate.hx
new file mode 100644
index 0000000..8477618
--- /dev/null
+++ b/src/game/TileTemplate.hx
@@ -0,0 +1,20 @@
+package game;
+
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+
+class TileTemplate extends LevelObjectTemplate
+{
+ public var tileGridX:Int;
+ public var tileGridY:Int;
+
+ public var tileTemplate:String;
+
+ public function new()
+ {
+ super();
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/behaviours/BaloonBehaviour.hx b/src/game/behaviours/BaloonBehaviour.hx
new file mode 100644
index 0000000..ac32d88
--- /dev/null
+++ b/src/game/behaviours/BaloonBehaviour.hx
@@ -0,0 +1,70 @@
+package game.behaviours;
+
+import game.CollisionCategory;
+import game.EnemyShip;
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class BaloonBehaviour extends BasicBehaviour
+{
+
+ public function new(subject:EnemyShip)
+ {
+ super(subject);
+ }
+
+ override public function init(dTime:Float):Void
+ {
+ updateFunction = oscillateDown;
+ }
+
+ private function oscillateDown(dTime:Float):Void
+ {
+ if (subject.speed.y < 50)
+ {
+ subject.speed.y += 30*dTime;
+ } else
+ {
+ updateFunction = oscillateUp;
+ }
+ }
+
+ private function oscillateUp(dTime:Float):Void
+ {
+ if (subject.speed.y > -50)
+ {
+ subject.speed.y -= 30*dTime;
+ } else
+ {
+ updateFunction = oscillateDown;
+ }
+ }
+
+ override public function checkCommonConditions():Void
+ {
+ if (subject.healthPoints <= 0 && !subject.shotDown)
+ {
+ subject.world.score += 1500;
+ subject.shotDown = true;
+ subject.unguidedProjectile = true;
+ subject.collisionCategory = CollisionCategory.PARTICLE;
+ subject.collisionMask = CollisionCategory.TILE;
+ updateFunction = goDownInFlames;
+ }
+ }
+
+ private function goDownInFlames(dTime:Float):Void
+ {
+ if (subject.shotDown && subject.speed.y < 300)
+ {
+ subject.speed.y += 200*dTime;
+ }
+ }
+
+ override public function respondToDamage():Void
+ {
+ super.respondToDamage();
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/behaviours/BasicBehaviour.hx b/src/game/behaviours/BasicBehaviour.hx
new file mode 100644
index 0000000..31362ac
--- /dev/null
+++ b/src/game/behaviours/BasicBehaviour.hx
@@ -0,0 +1,43 @@
+package game.behaviours;
+
+import game.EnemyShip;
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class BasicBehaviour implements IBehaviour
+{
+ public var updateFunction: Float -> Void;
+ public var subject:EnemyShip;
+
+ public function new(subject:EnemyShip)
+ {
+ this.subject = subject;
+ updateFunction = init;
+ }
+
+ public function update(dTime:Float):Void
+ {
+ checkCommonConditions();
+ if (updateFunction != null)
+ {
+ updateFunction(dTime);
+ }
+ }
+
+ public function checkCommonConditions():Void
+ {
+
+ }
+
+ public function init(dTime:Float):Void
+ {
+
+ }
+
+ public function respondToDamage():Void
+ {
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/behaviours/IBehaviour.hx b/src/game/behaviours/IBehaviour.hx
new file mode 100644
index 0000000..34a44e2
--- /dev/null
+++ b/src/game/behaviours/IBehaviour.hx
@@ -0,0 +1,10 @@
+package game.behaviours;
+
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+interface IBehaviour
+{
+ function update(dTime:Float):Void;
+}
\ No newline at end of file
diff --git a/src/game/behaviours/KamikazeBaloonBehaviour.hx b/src/game/behaviours/KamikazeBaloonBehaviour.hx
new file mode 100644
index 0000000..bd7e31c
--- /dev/null
+++ b/src/game/behaviours/KamikazeBaloonBehaviour.hx
@@ -0,0 +1,57 @@
+package game.behaviours;
+
+import game.CollisionCategory;
+import game.EnemyShip;
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class KamikazeBaloonBehaviour extends BasicBehaviour
+{
+ private var counter:Float;
+
+ public function new(subject:EnemyShip)
+ {
+ super(subject);
+ counter = 0;
+ }
+
+ override public function init(dTime:Float):Void
+ {
+ counter = 4 + Std.int(Math.random() * 8);
+ updateFunction = waitToExplode;
+ }
+
+ private function waitToExplode(dTime:Float):Void
+ {
+ counter -= dTime;
+ if (counter <= 0)
+ {
+ updateFunction = explode;
+ }
+ }
+
+ private function explode(dTime:Float):Void
+ {
+ for (i in 0...12)
+ {
+ subject.shoot(i * Math.PI * 2 / 12, 150);
+ }
+ subject.die();
+ updateFunction = null;
+ }
+
+ override public function checkCommonConditions():Void
+ {
+ if (subject.healthPoints <= 0 && !subject.shotDown)
+ {
+ subject.world.score += 1500;
+ subject.shotDown = true;
+ subject.unguidedProjectile = true;
+ subject.collisionCategory = CollisionCategory.PARTICLE;
+ subject.collisionMask = CollisionCategory.TILE;
+ subject.die();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/behaviours/TeslaBehaviourFrontalAssault.hx b/src/game/behaviours/TeslaBehaviourFrontalAssault.hx
new file mode 100644
index 0000000..dce816d
--- /dev/null
+++ b/src/game/behaviours/TeslaBehaviourFrontalAssault.hx
@@ -0,0 +1,41 @@
+package game.behaviours;
+
+import game.EnemyBullet;
+import game.EnemyShip;
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class TeslaBehaviourFrontalAssault implements IBehaviour
+{
+ private var subject:EnemyShip;
+ private var counter:Float;
+ private var shootCounter:Int;
+
+ public function new(subject:EnemyShip)
+ {
+ this.subject = subject;
+ counter = 0;
+ shootCounter = 1;
+ }
+
+ public function update(dTime:Float):Void
+ {
+ counter+=dTime;
+ if (counter > shootCounter*1.1)
+ {
+ subject.shootAtPlayer();
+ shootCounter++;
+ }
+ if (counter > 3)
+ {
+ subject.behaviour = new TeslaBehaviourRetreat(subject);
+ }
+
+ if (subject.healthPoints < 100)
+ {
+ subject.behaviour = new TeslaBehaviourRetreat(subject);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/behaviours/TeslaBehaviourGoDownInFlames.hx b/src/game/behaviours/TeslaBehaviourGoDownInFlames.hx
new file mode 100644
index 0000000..d8453c0
--- /dev/null
+++ b/src/game/behaviours/TeslaBehaviourGoDownInFlames.hx
@@ -0,0 +1,29 @@
+package game.behaviours;
+
+import game.EnemyShip;
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class TeslaBehaviourGoDownInFlames implements IBehaviour
+{
+ private var subject:EnemyShip;
+
+ public function new(subject:EnemyShip)
+ {
+ this.subject = subject;
+ }
+
+ public function update(dTime:Float):Void
+ {
+ if (subject.speed.y < 400)
+ {
+ subject.speed.y += 450*dTime;
+ }
+ if (subject.rotation > -Math.PI / 4)
+ {
+ subject.rotation -= Math.PI / 5*dTime;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/behaviours/TeslaBehaviourRam.hx b/src/game/behaviours/TeslaBehaviourRam.hx
new file mode 100644
index 0000000..5430ffc
--- /dev/null
+++ b/src/game/behaviours/TeslaBehaviourRam.hx
@@ -0,0 +1,50 @@
+package game.behaviours;
+
+import game.EnemyShip;
+import game.PlayerShip;
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class TeslaBehaviourRam implements IBehaviour
+{
+ private var subject:EnemyShip;
+ private var target:PlayerShip;
+ private var counter:Float;
+ private var shootCounter:Int;
+
+ public function new(subject:EnemyShip)
+ {
+ this.subject = subject;
+ counter = 0;
+ }
+
+ public function update(dTime:Float):Void
+ {
+ if (target == null)
+ {
+ target = subject.world.player;
+ }
+
+ counter+=dTime;
+ if (counter > shootCounter)
+ {
+ subject.shoot(Math.PI, 400);
+ shootCounter++;
+ }
+
+ if (target.y > subject.y + subject.speed.y / 5)
+ {
+ subject.speed.y += 180*dTime;
+ } else
+ {
+ subject.speed.y -= 180*dTime;
+ }
+
+ if (subject.healthPoints < 100)
+ {
+ subject.behaviour = new TeslaBehaviourRetreat(subject);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/behaviours/TeslaBehaviourRetreat.hx b/src/game/behaviours/TeslaBehaviourRetreat.hx
new file mode 100644
index 0000000..130a037
--- /dev/null
+++ b/src/game/behaviours/TeslaBehaviourRetreat.hx
@@ -0,0 +1,46 @@
+package game.behaviours;
+
+import game.CollisionCategory;
+import game.EnemyShip;
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class TeslaBehaviourRetreat implements IBehaviour
+{
+ private var subject:EnemyShip;
+ private var counter:Float;
+ private var shootCounter:Int;
+
+ public function new(subject:EnemyShip)
+ {
+ this.subject = subject;
+ counter = 0;
+ }
+
+ public function update(dTime:Float):Void
+ {
+ counter+=dTime;
+ if (counter > shootCounter*2)
+ {
+ subject.shootAtPlayer();
+ shootCounter++;
+ }
+
+ if (subject.speed.y > -1200)
+ {
+ subject.speed.y -= 300*dTime;
+ subject.rotation += Math.PI / 10*dTime;
+ }
+ if (subject.healthPoints < 0)
+ {
+ subject.shotDown = true;
+ subject.unguidedProjectile = true;
+ subject.collisionCategory = CollisionCategory.PARTICLE;
+ subject.collisionMask = CollisionCategory.TILE;
+ subject.behaviour = new TeslaBehaviourGoDownInFlames(subject);
+ subject.world.score += 5000;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/game/ui/GameOverScreen.hx b/src/game/ui/GameOverScreen.hx
new file mode 100644
index 0000000..83fd71b
--- /dev/null
+++ b/src/game/ui/GameOverScreen.hx
@@ -0,0 +1,104 @@
+package game.ui;
+
+#if (!android && !iphone)
+
+#end
+import flash.display.Bitmap;
+import flash.display.BitmapData;
+import flash.display.Sprite;
+import flash.text.TextField;
+import flash.text.TextFormat;
+import flash.text.TextFormatAlign;
+import game.GameWorld;
+import motion.Actuate;
+import openfl.Assets;
+
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+
+class GameOverScreen extends Sprite
+{
+
+
+ private var darkScreen:Bitmap;
+ private var gameOverText:Bitmap;
+ private var gameWorld:GameWorld;
+ private var scoreText:TextField;
+ private var restartText:String;
+ private var screenWidth:Float;
+ private var screenHeight:Float;
+
+ public function new(gameWorld:GameWorld, screenWidth:Float, screenHeight:Float)
+ {
+ this.screenWidth = screenWidth;
+ this.screenHeight = screenHeight;
+ this.gameWorld = gameWorld;
+ super();
+
+ #if (android || iphone)
+ restartText = "Tap anywhere to restart";
+ #else
+ restartText = "Click anywhere to restart";
+ #end
+
+ darkScreen = new Bitmap(new BitmapData(1, 1, true, 0xFF000000));
+ darkScreen.scaleX = screenWidth;
+ darkScreen.scaleY = screenHeight;
+ darkScreen.alpha = 0;
+ addChild(darkScreen);
+
+ gameOverText = new Bitmap(Assets.getBitmapData("assets/ui/gameOverText.png"));
+ gameOverText.x = (screenWidth - gameOverText.width) / 2;
+ gameOverText.y = Std.int(screenHeight/2 - 100);
+ gameOverText.alpha = 0;
+ addChild(gameOverText);
+
+ scoreText = new TextField();
+ scoreText.alpha = 0;
+ scoreText.embedFonts = true;
+ scoreText.selectable = false;
+ scoreText.width = screenWidth;
+ scoreText.y = gameOverText.y + 60;
+ addChild(scoreText);
+
+ var scoreTF:TextFormat = scoreText.defaultTextFormat;
+ scoreTF.font = FontManager.mainFont.fontName;
+ scoreTF.bold = true;
+ scoreTF.size = 24;
+ scoreTF.align = TextFormatAlign.CENTER;
+ scoreTF.color = 0xFFFFFF;
+ scoreText.defaultTextFormat = scoreTF;
+
+
+ #if (android || iphone)
+ darkScreen.alpha = 0.6;
+ gameOverText.alpha = 1;
+ scoreText.alpha = 1;
+ #end
+ }
+
+ public function show():Void
+ {
+ visible = true;
+ #if (!android && !iphone)
+ Actuate.tween(darkScreen, 8, { alpha: 0.6 } );
+ Actuate.tween(gameOverText, 1, { alpha: 1 } );
+ Actuate.tween(scoreText, 3, { alpha: 1 } );
+ #end
+ scoreText.text = "SCORE: " + Std.string(gameWorld.score) + "\n\n" + restartText;
+ }
+
+ public function hide():Void
+ {
+ visible = false;
+ #if (!android && !iphone)
+ Actuate.stop(darkScreen, "alpha", false, false);
+ Actuate.stop(gameOverText, "alpha", false, false);
+ darkScreen.alpha = 0;
+ gameOverText.alpha = 0;
+ #end
+ }
+
+}
\ No newline at end of file
diff --git a/src/sphaeraGravita/collision/AABB.hx b/src/sphaeraGravita/collision/AABB.hx
new file mode 100644
index 0000000..f187584
--- /dev/null
+++ b/src/sphaeraGravita/collision/AABB.hx
@@ -0,0 +1,94 @@
+package sphaeraGravita.collision;
+import sphaeraGravita.math.Vector2D;
+
+/**
+ * ...
+ * @author Dimonte
+ */
+class AABB
+{
+ private var bottomRight:Vector2D;
+ private var topLeft:Vector2D;
+ private var topRight:Vector2D;
+ private var bottomLeft:Vector2D;
+ public var lowerBound:Vector2D;
+ public var upperBound:Vector2D;
+
+ public function new()
+ {
+ lowerBound = new Vector2D();
+ upperBound = new Vector2D();
+ topLeft = new Vector2D();
+ topRight = new Vector2D();
+ bottomRight = new Vector2D();
+ bottomLeft = new Vector2D();
+ }
+
+ public function getWidth():Float
+ {
+ return upperBound.x - lowerBound.x;
+ }
+
+ public function getHeight():Float
+ {
+ return upperBound.y - lowerBound.y;
+ }
+
+ public function containsPoint(point:Vector2D):Bool
+ {
+ if (point.x < lowerBound.x)
+ return false;
+ if (point.x > upperBound.x)
+ return false;
+ if (point.y < lowerBound.y)
+ return false;
+ if (point.y > upperBound.y)
+ return false;
+ return true;
+ }
+
+ public function getTopLeftCorner():Vector2D
+ {
+ topLeft.x = lowerBound.x;
+ topLeft.y = lowerBound.y;
+ return topLeft;
+ }
+
+ public function getTopRightCorner():Vector2D
+ {
+ topRight.x = upperBound.x;
+ topRight.y = lowerBound.y;
+ return topRight;
+ }
+
+ public function getBottomLeftCorner():Vector2D
+ {
+ bottomLeft.x = lowerBound.x;
+ bottomLeft.y = upperBound.y;
+ return bottomLeft;
+ }
+
+ public function getBottomRightCorner():Vector2D
+ {
+
+ bottomRight.x = upperBound.x;
+ bottomRight.y = upperBound.y;
+ return bottomRight;
+ }
+
+ static public function asMinMax(minX:Float, minY:Float, maxX:Float, maxY:Float):AABB
+ {
+ var aabb:AABB = new AABB();
+ aabb.lowerBound.x = minX;
+ aabb.lowerBound.y = minY;
+ aabb.upperBound.x = maxX;
+ aabb.upperBound.y = maxY;
+ return aabb;
+ }
+
+ public function toString():String
+ {
+ return "minX: " + lowerBound.x + ", minY: " + lowerBound.y + ", width: " + getWidth() + ", height: " + getHeight();
+ }
+
+}
\ No newline at end of file
diff --git a/src/sphaeraGravita/collision/CollidingEntity.hx b/src/sphaeraGravita/collision/CollidingEntity.hx
new file mode 100644
index 0000000..1874ab3
--- /dev/null
+++ b/src/sphaeraGravita/collision/CollidingEntity.hx
@@ -0,0 +1,56 @@
+package sphaeraGravita.collision;
+import game.CollisionCategory;
+
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+class CollidingEntity
+{
+ public var parent:CollidingEntity;
+
+ public var collisionCategory(get, set):Int;
+
+ var _collisionCategory:Int = CollisionCategory.INHERIT;
+
+ public function get_collisionCategory():Int
+ {
+ if (_collisionCategory == CollisionCategory.INHERIT)
+ {
+ if (parent != null)
+ {
+ return parent.collisionCategory;
+ }
+ }
+ return _collisionCategory;
+ }
+
+ public function set_collisionCategory(value:Int):Int
+ {
+ _collisionCategory = value;
+ return collisionCategory;
+ }
+
+ public var collisionMask(get, set):Int;
+
+ var _collisionMask:Int;
+
+ public function get_collisionMask():Int
+ {
+ if (_collisionMask == CollisionCategory.INHERIT)
+ {
+ if (parent != null)
+ {
+ return parent.collisionMask;
+ }
+ }
+ return _collisionMask;
+ }
+
+ public function set_collisionMask(value:Int):Int
+ {
+ _collisionMask = value;
+ return collisionMask;
+ }
+
+}
\ No newline at end of file
diff --git a/src/sphaeraGravita/collision/CollisionEngine.hx b/src/sphaeraGravita/collision/CollisionEngine.hx
new file mode 100644
index 0000000..fa93f73
--- /dev/null
+++ b/src/sphaeraGravita/collision/CollisionEngine.hx
@@ -0,0 +1,623 @@
+package sphaeraGravita.collision;
+
+import dataStructures.DLLNode;
+import game.CollisionCategory;
+import game.GameEntity;
+import sphaeraGravita.collision.PhysicalBody;
+import sphaeraGravita.math.Vector2D;
+import sphaeraGravita.shapes.BaseShape;
+import sphaeraGravita.shapes.CircleShape;
+import sphaeraGravita.shapes.Polygon;
+import sphaeraGravita.shapes.ShapeType;
+
+/**
+ * ...
+ * @author Dimonte
+ */
+class CollisionEngine
+{
+ /**
+ * WARNING! Gets overwritten every time project<...> functions are called.
+ */
+ private var projectionResult:ProjectionResult;
+
+ private var intervalOne:Float;
+ private var intervalTwo:Float;
+ private var min:Float;
+ private var max:Float;
+ private var projectionPoint:Float;
+ private var verticeNum:Int;
+ private var i:Int;
+
+ public function new()
+ {
+ projectionResult = new ProjectionResult();
+ }
+
+ public function collideBodies(entityOne:PhysicalBody, entityTwo:PhysicalBody):Void
+ {
+
+ //trace("collideBodies > " + entityOne + " - " + entityTwo);
+
+ if (entityOne.dead || entityTwo.dead)
+ {
+ return;
+ }
+ if(!matchCollisionCategories(entityOne, entityTwo))
+ {
+ return;
+ }
+ if (!queryBoundsIntersection(entityOne, entityTwo))
+ {
+ return;
+ }
+ //trace("full cd");
+ var collisionResult:CollisionResult;
+ var bodyOneShape:BaseShape = entityOne.shapeList;
+ while (bodyOneShape != null)
+ {
+ var bodyTwoShape:BaseShape;
+ bodyTwoShape = entityTwo.shapeList;
+ while (bodyTwoShape != null)
+ {
+ if (bodyOneShape.collisionMask != 0 || bodyOneShape.collisionCategory != CollisionCategory.INHERIT || bodyTwoShape.collisionMask != 0 || bodyTwoShape.collisionCategory != CollisionCategory.INHERIT)
+ {
+ if (!matchCollisionCategories(bodyOneShape, bodyTwoShape))
+ {
+ bodyTwoShape = bodyTwoShape.next;
+ continue;
+ }
+ }
+
+ //trace("bodyTwoShape : " + bodyTwoShape);
+ if (bodyOneShape.sensor || bodyTwoShape.sensor)
+ {
+ //trace("huh?");
+ if (queryShapes(bodyOneShape, bodyTwoShape))
+ {
+ entityOne.reactToCollision(entityTwo, bodyOneShape, bodyTwoShape);
+ entityTwo.reactToCollision(entityOne, bodyTwoShape, bodyOneShape);
+ }
+ }
+ else
+ {
+ collisionResult = collideShapes(bodyOneShape, bodyTwoShape);
+ if (collisionResult != null)
+ {
+ if (collisionResult.collision)
+ {
+ collisionResult.calculateMTDVector();
+ var bounceCoefficient:Float = entityOne.bounceFactor * entityTwo.bounceFactor;
+ entityOne.position.x += collisionResult.mtdVector.x * bounceCoefficient;
+ entityOne.position.y += collisionResult.mtdVector.y * bounceCoefficient;
+ var frictionCoefficient:Float = entityOne.frictionFactor * entityTwo.frictionFactor;
+ var firstReflectingComponent:Vector2D = Vector2D.project(entityOne.speed, collisionResult.mtdAxis).invert().multiply(bounceCoefficient);
+ var firstFrictionComponent:Vector2D = Vector2D.project(entityOne.speed, collisionResult.mtdAxis.getNormalRight()).multiply(frictionCoefficient);
+ var speedProjection:Vector2D = Vector2D.project(entityOne.speed, collisionResult.mtdAxis);
+ if (Vector2D.dotProduct(entityOne.speed, collisionResult.mtdVector) < 0)
+ {
+ entityOne.speed = (firstReflectingComponent.add(firstFrictionComponent));
+ }
+
+ //TODO entityTwo speed after collision
+
+ entityOne.reactToCollision(entityTwo, bodyOneShape, bodyTwoShape);
+ entityTwo.reactToCollision(entityOne, bodyTwoShape, bodyOneShape);
+ }
+ }
+ }
+ bodyTwoShape = bodyTwoShape.next;
+ }
+ bodyOneShape = bodyOneShape.next;
+ }
+ }
+
+ public function matchCollisionCategories(entityOne:CollidingEntity, entityTwo:CollidingEntity):Bool
+ {
+ //trace("matchCollisionCategories > " + entityOne + " - " + entityTwo);
+
+ //trace("entityOne.collisionMask " + entityOne.collisionMask);
+ //trace("entityTwo.collisionCategory " + entityTwo.collisionCategory);
+
+ if (entityOne.collisionMask != 0 && (entityOne.collisionMask & entityTwo.collisionCategory == 0))
+ return false;
+
+ //trace("entityTwo.collisionMask " + entityTwo.collisionMask);
+ //trace("entityOne.collisionCategory " + entityOne.collisionCategory);
+
+ if (entityTwo.collisionMask != 0 && (entityTwo.collisionMask & entityOne.collisionCategory == 0))
+ return false;
+
+ return true;
+ }
+
+ public function collideShapes(shapeOne:BaseShape, shapeTwo:BaseShape):CollisionResult
+ {
+ var shapeCollisionResult:CollisionResult = null;
+ var tempCollisionResult:CollisionResult = null;
+ if (shapeOne.type == ShapeType.POLYGON_SHAPE)
+ {
+ if (shapeTwo.type == ShapeType.POLYGON_SHAPE)
+ {
+ shapeCollisionResult = detectPolygons(cast(shapeOne,Polygon), cast(shapeTwo,Polygon));
+ }
+ else if (shapeTwo.type == ShapeType.CIRCLE_SHAPE)
+ {
+ shapeCollisionResult = detectPolyCircle(cast(shapeTwo, CircleShape), cast(shapeOne, Polygon));
+ if (shapeCollisionResult != null)
+ {
+ shapeCollisionResult.mtdAmount = -shapeCollisionResult.mtdAmount;
+ }
+ }
+ }
+ else if (shapeOne.type == ShapeType.CIRCLE_SHAPE)
+ {
+ if (shapeTwo.type == ShapeType.CIRCLE_SHAPE)
+ {
+ shapeCollisionResult = detectCircleCircle(cast(shapeOne,CircleShape), cast(shapeTwo,CircleShape));
+ }
+ else if (shapeTwo.type == ShapeType.POLYGON_SHAPE)
+ {
+ shapeCollisionResult = detectPolyCircle(cast(shapeOne,CircleShape), cast(shapeTwo,Polygon));
+ }
+ }
+ return shapeCollisionResult;
+ }
+
+ public function queryShapes(shapeOne:BaseShape, shapeTwo:BaseShape):Bool
+ {
+ var tempCollisionResult:CollisionResult = null;
+ if (shapeOne.type == ShapeType.POLYGON_SHAPE)
+ {
+ if (shapeTwo.type == ShapeType.POLYGON_SHAPE)
+ {
+ tempCollisionResult = detectPolygons(cast(shapeOne,Polygon), cast(shapeTwo,Polygon));
+ }
+ else if (shapeTwo.type == ShapeType.CIRCLE_SHAPE)
+ {
+ tempCollisionResult = detectPolyCircle(cast(shapeTwo,CircleShape), cast(shapeOne,Polygon));
+ }
+ }
+ else if (shapeOne.type == ShapeType.CIRCLE_SHAPE)
+ {
+ if (shapeTwo.type == ShapeType.CIRCLE_SHAPE)
+ {
+ tempCollisionResult = detectCircleCircle(cast(shapeOne,CircleShape), cast(shapeTwo,CircleShape));
+ }
+ else if (shapeTwo.type == ShapeType.POLYGON_SHAPE)
+ {
+ tempCollisionResult = detectPolyCircle(cast(shapeOne,CircleShape), cast(shapeTwo,Polygon));
+ }
+ }
+ if (tempCollisionResult != null)
+ {
+ if (tempCollisionResult.collision)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ *
+ * @param bodyOne
+ * @param bodyTwo
+ * @return collision result, mtd is for the FIRST body
+ */
+ public function collide(bodyOne:PhysicalBody, bodyTwo:PhysicalBody):CollisionResult
+ {
+ var collisionResult:CollisionResult = new CollisionResult();
+ collisionResult.mtdAmount = Math.POSITIVE_INFINITY;
+ var tempCollisionResult:CollisionResult = collisionResult;
+ var bodyOneShape:BaseShape;
+ var bodyTwoShape:BaseShape;
+ if (queryBoundsIntersection(bodyOne, bodyTwo))
+ {
+ bodyOneShape = bodyOne.shapeList;
+ while (bodyOneShape != null)
+ {
+ bodyTwoShape = bodyTwo.shapeList;
+ while (bodyTwoShape != null)
+ {
+ if (bodyOneShape.type == ShapeType.POLYGON_SHAPE)
+ {
+ if (bodyTwoShape.type == ShapeType.POLYGON_SHAPE)
+ {
+ tempCollisionResult = detectPolygons(cast(bodyOneShape,Polygon), cast(bodyTwoShape,Polygon));
+ }
+ else if (bodyTwoShape.type == ShapeType.CIRCLE_SHAPE)
+ {
+ tempCollisionResult = detectPolyCircle(cast(bodyTwoShape,CircleShape), cast(bodyOneShape,Polygon));
+ tempCollisionResult.mtdAmount = -tempCollisionResult.mtdAmount;
+ }
+ }
+ else if (bodyOneShape.type == ShapeType.CIRCLE_SHAPE)
+ {
+ if (bodyTwoShape.type == ShapeType.CIRCLE_SHAPE)
+ {
+ tempCollisionResult = detectCircleCircle(cast(bodyOneShape,CircleShape), cast(bodyTwoShape,CircleShape));
+ }
+ else if (bodyTwoShape.type == ShapeType.POLYGON_SHAPE)
+ {
+ tempCollisionResult = detectPolyCircle(cast(bodyOneShape, CircleShape), cast(bodyTwoShape,Polygon));
+ }
+ }
+ if(tempCollisionResult.collision)
+ {
+ if (!collisionResult.collision)
+ {
+ collisionResult = tempCollisionResult;
+ collisionResult.calculateMTDVector();
+ } else {
+ collisionResult.mtdVector.add(tempCollisionResult.calculateMTDVector());
+ }
+ }
+ bodyTwoShape = bodyTwoShape.next;
+ }
+ bodyOneShape = bodyOneShape.next;
+ }
+ }
+ // TODO sensor shapes
+ // TODO immidiate vs delayed logic response
+ /*var bodyOneShapeOne:BaseShape = bodyOne.shapeList.head().val as BaseShape;
+ var bodyTwoShapeOne:BaseShape = bodyTwo.shapeList.head().val as BaseShape;
+ if ((bodyTwoShapeOne.type == ShapeType.AABB_SHAPE) && (bodyOneShapeOne.type == ShapeType.AABB_SHAPE))
+ {
+ collisionResult = collideAABBToAABB(bodyOneShapeOne as AABB, bodyTwoShapeOne as AABB);
+ if (collisionResult.collision)
+ {
+ //trace("Collision! " + collisionResult.mtdVector.toString());
+ bodyOne.position.x += collisionResult.mtdVector.x;
+ bodyOne.position.y += collisionResult.mtdVector.y;
+ var firstReflectingComponent:Vector2D = Vector2D.project(bodyOne.speed.clone().invert(), collisionResult.mtdAxis).multiply(0.9);
+ var firstFrictionComponent:Vector2D = Vector2D.project(bodyOne.speed, collisionResult.mtdAxis.getNormalRight()).multiply(0.8);
+ bodyOne.speed = (firstReflectingComponent.add(firstFrictionComponent));
+ }
+ }*/
+ return collisionResult;
+ }
+
+ public function queryBoundsIntersection(bodyOne:PhysicalBody, bodyTwo:PhysicalBody):Bool
+ {
+ var bodyOneLowerBound:Vector2D = bodyOne.worldAABB.lowerBound;
+ var bodyOneUpperBound:Vector2D = bodyOne.worldAABB.upperBound;
+ var bodyTwoLowerBound:Vector2D = bodyTwo.worldAABB.lowerBound;
+ var bodyTwoUpperBound:Vector2D = bodyTwo.worldAABB.upperBound;
+
+ if (bodyOneLowerBound.x >= bodyTwoUpperBound.x)
+ {
+ return false;
+ }
+ if (bodyOneLowerBound.y >= bodyTwoUpperBound.y)
+ {
+ return false;
+ }
+ if (bodyOneUpperBound.x <= bodyTwoLowerBound.x)
+ {
+ return false;
+ }
+ if (bodyOneUpperBound.y <= bodyTwoLowerBound.y)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ private function detectPolygons(firstPoly:Polygon, secondPoly:Polygon):Null
+ {
+ var resultMTD:Float = Math.POSITIVE_INFINITY;
+ var mtdAxis:Vector2D = null;
+
+ var testAxisList:Array = new Array();
+
+ var firstPolyVertexNum:Int = firstPoly.getNumVertices();
+ var secondPolyVertexNum:Int = secondPoly.getNumVertices();
+ var totalVerges:Int = firstPolyVertexNum + secondPolyVertexNum;
+ var firstVerticeSet:Array = [];
+ var body:PhysicalBody = firstPoly.body;
+ for (i in 0...firstPoly.getNumVertices())
+ {
+ firstVerticeSet[i] = body.localToWorld(firstPoly.vertices[i]);
+ testAxisList.push(firstPoly.normals[i].clone().applyXform(body.xform));
+ }
+
+ var firstMin:Float = 0;
+ var firstMax:Float = 0;
+ var secondMin:Float = 0;
+ var secondMax:Float = 0;
+ var intervalOneAbs:Float = 0;
+ var intervalTwoAbs:Float = 0;
+ var firstPolyProjection:ProjectionResult;
+ var secondPolyProjection:ProjectionResult;
+
+ var secondVerticeSet:Array = [];
+ body = secondPoly.body;
+ for (i in 0...secondPoly.getNumVertices())
+ {
+ secondVerticeSet[i] = secondPoly.body.localToWorld(secondPoly.vertices[i]);
+ testAxisList.push(secondPoly.normals[i].clone().applyXform(body.xform));
+ }
+ for (i in 0...totalVerges)
+ {
+ var testAxis:Vector2D;
+ testAxis = testAxisList[i];
+
+ firstPolyProjection = projectVerticeSetOnAxis(firstVerticeSet, testAxis);
+ firstMin = firstPolyProjection.min;
+ firstMax = firstPolyProjection.max;
+
+ secondPolyProjection = projectVerticeSetOnAxis(secondVerticeSet, testAxis);
+ secondMin = secondPolyProjection.min;
+ secondMax = secondPolyProjection.max;
+
+ if (secondMin > firstMax)
+ {
+ return null;
+ }
+ if (firstMin > secondMax)
+ {
+ return null;
+ }
+
+ intervalOne = secondMin - firstMax;
+ intervalTwo = secondMax - firstMin;
+ intervalOneAbs = intervalOne < 0 ? -intervalOne:intervalOne;
+ intervalTwoAbs = intervalTwo < 0 ? -intervalTwo:intervalTwo;
+
+ // use faster math for ABSes or get rid of 'em
+ if (intervalTwoAbs < intervalOneAbs)
+ {
+ intervalOneAbs = intervalTwoAbs;
+ if (intervalTwo < 0)
+ {
+ testAxis = testAxis.clone().invert();
+ }
+ } else {
+ if (intervalOne < 0)
+ {
+ testAxis = testAxis.clone().invert();
+ }
+ }
+
+ if (intervalOneAbs < resultMTD)
+ {
+ //trace(interval);
+ resultMTD = intervalOneAbs;
+ mtdAxis = testAxis.clone();
+ }
+ }
+
+ var result:CollisionResult = new CollisionResult();
+ result.mtdAmount = resultMTD;
+ result.mtdAxis = mtdAxis;
+ result.collision = true;
+
+ return result;
+ }
+
+ public function detectPolyCircle(circle:CircleShape, poly:Polygon):Null
+ {
+
+
+ var resultMTD:Float = Math.POSITIVE_INFINITY;
+ var mtdAxis:Vector2D = null;
+ var collision:Bool = true;
+
+ var circlePosition:Vector2D = circle.body.localToWorld(circle.position);
+
+ var totalEdges:Int = poly.getNumVertices();
+
+ var polyVerticeSet:Array = [];
+ for (i in 0...totalEdges)
+ {
+ polyVerticeSet[i] = poly.body.localToWorld(poly.vertices[i]);
+ }
+
+ var testAxis:Vector2D;
+ var circleProjection:ProjectionResult;
+ var secondPolyProjection:ProjectionResult;
+ var intervalOneAbs:Float;
+ var intervalTwoAbs:Float;
+
+ var circleMin:Float = 0;
+ var circleMax:Float = 0;
+ var polyMin:Float = 0;
+ var polyMax:Float = 0;
+ var intervalOneAbs:Float = 0;
+ var intervalTwoAbs:Float = 0;
+
+ for (i in 0...totalEdges)
+ {
+ //*
+ testAxis = poly.normals[i].clone().applyXform(poly.body.xform);
+ /*/
+ testAxis = poly.normals[i].clone();
+ //*/
+
+ circleProjection = projectCircleOnAxis(circle, testAxis);
+ circleMin = circleProjection.min;
+ circleMax = circleProjection.max;
+
+ secondPolyProjection = projectVerticeSetOnAxis(polyVerticeSet, testAxis);
+ polyMin = secondPolyProjection.min;
+ polyMax = secondPolyProjection.max;
+
+ if (polyMin > circleMax)
+ {
+ return null;
+ }
+ if (circleMin > polyMax)
+ {
+ return null;
+ }
+ intervalOne = polyMin - circleMax;
+ intervalTwo = polyMax - circleMin;
+ intervalOneAbs = intervalOne < 0 ? -intervalOne:intervalOne;
+ intervalTwoAbs = intervalTwo < 0 ? -intervalTwo:intervalTwo;
+ // use faster math for ABSes or get rid of 'em
+ if (intervalTwoAbs < intervalOneAbs)
+ {
+ intervalOneAbs = intervalTwoAbs;
+ if (intervalTwo < 0)
+ {
+ testAxis = testAxis.invert();
+ }
+ } else {
+ if (intervalOne < 0)
+ {
+ testAxis = testAxis.invert();
+ }
+ }
+
+ if (intervalOneAbs < resultMTD)
+ {
+ resultMTD = intervalOneAbs;
+ mtdAxis = testAxis;
+ }
+ }
+ for (i in 0...totalEdges)
+ {
+ testAxis = circle.body.localToWorld(circle.position).subtract(poly.body.localToWorld(poly.vertices[i])).normalize();
+
+ circleProjection = projectCircleOnAxis(circle, testAxis);
+ circleMin = circleProjection.min;
+ circleMax = circleProjection.max;
+ secondPolyProjection = projectVerticeSetOnAxis(polyVerticeSet, testAxis);
+ polyMin = secondPolyProjection.min;
+ polyMax = secondPolyProjection.max;
+
+ if (polyMin > circleMax)
+ {
+ return null;
+ }
+ if (circleMin > polyMax)
+ {
+ return null;
+ }
+ intervalOne = polyMin - circleMax;
+ intervalTwo = polyMax - circleMin;
+ intervalOneAbs = intervalOne < 0 ? -intervalOne:intervalOne;
+ intervalTwoAbs = intervalTwo < 0 ? -intervalTwo:intervalTwo;
+ // use faster math for ABSes or get rid of 'em
+ if (intervalTwoAbs < intervalOneAbs)
+ {
+ intervalOneAbs = intervalTwoAbs;
+ if (intervalTwo < 0)
+ {
+ testAxis = testAxis.invert();
+ }
+ } else {
+ if (intervalOne < 0)
+ {
+ testAxis = testAxis.invert();
+ }
+ }
+
+ if (intervalOneAbs < resultMTD)
+ {
+ resultMTD = intervalOneAbs;
+ mtdAxis = testAxis;
+ }
+ }
+
+ var result:CollisionResult = new CollisionResult();
+ result.mtdAmount = resultMTD;
+ result.mtdAxis = mtdAxis;
+ result.collision = true;
+
+ return result;
+ //*/
+ }
+
+ private function detectCircleCircle(circleOne:CircleShape, circleTwo:CircleShape):Null
+ {
+ var circleOneWorldPosition:Vector2D = circleOne.body.localToWorld(circleOne.position);
+ var circleTwoWorldPosition:Vector2D = circleTwo.body.localToWorld(circleTwo.position);
+ var distanceSquared:Float = Math.pow(circleTwoWorldPosition.x - circleOneWorldPosition.x, 2) + Math.pow(circleTwoWorldPosition.y - circleOneWorldPosition.y, 2);
+ var radiusesSquared:Float = (circleOne.radius + circleTwo.radius)*(circleOne.radius + circleTwo.radius);
+ if (distanceSquared >= radiusesSquared)
+ {
+ return null;
+ }
+ var result:CollisionResult = new CollisionResult();
+ result.collision = true;
+ result.mtdAmount = Math.sqrt(radiusesSquared) - Math.sqrt(distanceSquared);
+ result.mtdAxis = circleOneWorldPosition.clone().subtract(circleTwoWorldPosition).normalize();
+ return result;
+ }
+
+ private function projectVerticeSetOnAxis(verticeSet:Array, axis:Vector2D):ProjectionResult
+ {
+ verticeNum = verticeSet.length;
+ min = Vector2D.dotProduct(verticeSet[0], axis);
+ max = Vector2D.dotProduct(verticeSet[0], axis);
+ for (i in 1...verticeNum)
+ {
+ projectionPoint = Vector2D.dotProduct(verticeSet[i], axis);
+ if (projectionPoint < min)
+ {
+ min = projectionPoint;
+ }
+ if (projectionPoint > max)
+ {
+ max = projectionPoint;
+ }
+ }
+
+ projectionResult.min = min;
+ projectionResult.max = max;
+
+ return projectionResult;
+ }
+
+ private function projectPolygonOnAxis(polygon:Polygon, axis:Vector2D):ProjectionResult
+ {
+ var body:PhysicalBody = polygon.body;
+ var min:Float = Vector2D.dotProduct(body.localToWorld(polygon.vertices[0]), axis);
+ var max:Float = Vector2D.dotProduct(body.localToWorld(polygon.vertices[0]), axis);
+ var projectionPoint:Float;
+ for (i in 1...polygon.getNumVertices())
+ {
+ projectionPoint = Vector2D.dotProduct(body.localToWorld(polygon.vertices[i]), axis);
+ if (projectionPoint < min)
+ min = projectionPoint;
+ if (projectionPoint > max)
+ max = projectionPoint;
+ }
+
+ projectionResult.min = min;
+ projectionResult.max = max;
+
+ return projectionResult;
+ }
+
+ private function closestPointOnLineSegment(startPoint:Vector2D, segment:Vector2D, point:Vector2D):Vector2D
+ {
+ var closestPoint:Vector2D;
+
+ var testDotProduct:Float = Vector2D.dotProduct(segment, point.clone().subtract(startPoint));
+ var segmentLengthSquared:Float = segment.getLengthSquared();
+
+ if (testDotProduct <= 0)
+ {
+ closestPoint = startPoint.clone();
+ } else if(testDotProduct >= segmentLengthSquared) {
+ closestPoint = startPoint.clone().add(segment);
+ } else {
+ var segmentPart:Float = testDotProduct / segmentLengthSquared;
+ closestPoint = startPoint.clone().add(segment.clone().multiply(segmentPart));
+ }
+
+ return closestPoint;
+ }
+
+ private function projectCircleOnAxis(circle:CircleShape, axis:Vector2D):ProjectionResult
+ {
+ var center:Float = Vector2D.dotProduct(circle.body.localToWorld(circle.position), axis);
+ projectionResult.min = center - circle.radius;
+ projectionResult.max = center + circle.radius;
+ return projectionResult;
+ }
+
+}
\ No newline at end of file
diff --git a/src/sphaeraGravita/collision/CollisionResult.hx b/src/sphaeraGravita/collision/CollisionResult.hx
new file mode 100644
index 0000000..86328ef
--- /dev/null
+++ b/src/sphaeraGravita/collision/CollisionResult.hx
@@ -0,0 +1,26 @@
+package sphaeraGravita.collision;
+
+import sphaeraGravita.math.Vector2D;
+/**
+ * ...
+ * @author Dimonte
+ */
+class CollisionResult
+{
+ public var collision:Bool;
+ public var mtdAmount:Float;
+ public var mtdAxis:Vector2D;
+ public var mtdVector:Vector2D;
+
+ public function new ()
+ {
+
+ }
+
+ public function calculateMTDVector():Vector2D
+ {
+ mtdVector = mtdAxis.clone().multiply(mtdAmount);
+ return mtdVector;
+ }
+
+}
\ No newline at end of file
diff --git a/src/sphaeraGravita/collision/PhysicalBody.hx b/src/sphaeraGravita/collision/PhysicalBody.hx
new file mode 100644
index 0000000..9608dae
--- /dev/null
+++ b/src/sphaeraGravita/collision/PhysicalBody.hx
@@ -0,0 +1,207 @@
+package sphaeraGravita.collision;
+
+
+import dataStructures.DLL;
+import dataStructures.DLLNode;
+import sphaeraGravita.math.RotationMatrix;
+import sphaeraGravita.math.Vector2D;
+import sphaeraGravita.shapes.BaseShape;
+import sphaeraGravita.spacePartitioning.GridCell;
+//import sphaeraGravita.shapes.BaseShape;
+
+/**
+ * ...
+ * @author Dimonte
+ */
+class PhysicalBody extends CollidingEntity
+{
+
+ public var boundingAABB:AABB;
+ public var xformedBoundingAABB:AABB;
+ public var worldAABB:AABB;
+ public var shapeList:BaseShape;
+ public var colliding:Bool;
+ public var gridBound:Bool;
+ public var overlappingCells:Array;
+ public var fixed:Bool;
+ public var dead:Bool;
+
+ public var position:Vector2D;
+ public var xform:RotationMatrix;
+ public var speed:Vector2D;
+
+ public var bounceFactor:Float;
+ public var frictionFactor:Float;
+
+ public var x(get,set):Float;
+ public var y(get,set):Float;
+ public var rotation(get,set):Float;
+
+ public function new()
+ {
+ bounceFactor = 1;
+ frictionFactor = 1;
+ position = new Vector2D();
+ speed = new Vector2D();
+ xform = new RotationMatrix();
+ }
+
+ public function clearShapes():Void
+ {
+ shapeList = null;
+ }
+
+ public function addShape(shape:BaseShape):Void
+ {
+ shape.parent = shape.body = this;
+
+ if (shapeList != null) {
+ var shapeNode:BaseShape = shapeList;
+ while (shapeNode.next != null) {
+ shapeNode = shapeNode.next;
+ }
+ shapeNode.next = shape;
+ } else {
+ shapeList = shape;
+ }
+ }
+
+ public function init():Void
+ {
+ var minX:Float = Math.POSITIVE_INFINITY;
+ var minY:Float = Math.POSITIVE_INFINITY;
+ var maxX:Float = Math.NEGATIVE_INFINITY;
+ var maxY:Float = Math.NEGATIVE_INFINITY;
+
+ var shape:BaseShape = shapeList;
+
+ // if there's no shapes inside, zeroes abound!
+ if (shape == null)
+ {
+ minX = minY = maxX = maxY = 0;
+ }
+
+ while (shape != null)
+ {
+ minX = Math.min(minX, shape.getBoundingAABB().lowerBound.x);
+ minY = Math.min(minY, shape.getBoundingAABB().lowerBound.y);
+ maxX = Math.max(maxX, shape.getBoundingAABB().upperBound.x);
+ maxY = Math.max(maxY, shape.getBoundingAABB().upperBound.y);
+ shape = shape.next;
+ }
+ boundingAABB = AABB.asMinMax(minX, minY, maxX, maxY);
+ xformedBoundingAABB = AABB.asMinMax(minX, minY, maxX, maxY);
+ worldAABB = AABB.asMinMax(minX, minY, maxX, maxY);
+ }
+
+ public function updateWorldCache():Void
+ {
+ if (worldAABB == null)
+ {
+ //trace(this);
+ return;
+ }
+ worldAABB.lowerBound.x = xformedBoundingAABB.lowerBound.x + position.x;
+ worldAABB.lowerBound.y = xformedBoundingAABB.lowerBound.y + position.y;
+ worldAABB.upperBound.x = xformedBoundingAABB.upperBound.x + position.x;
+ worldAABB.upperBound.y = xformedBoundingAABB.upperBound.y + position.y;
+ }
+
+ private function recalculateXformedAABB():Void
+ {
+ var tl:Vector2D = boundingAABB.getTopLeftCorner().applyXform(xform);
+ var tr:Vector2D = boundingAABB.getTopRightCorner().applyXform(xform);
+ var bl:Vector2D = boundingAABB.getBottomLeftCorner().applyXform(xform);
+ var br:Vector2D = boundingAABB.getBottomRightCorner().applyXform(xform);
+ var minX:Float = Math.min(Math.min(tl.x, tr.x), Math.min(bl.x, br.x));
+ var minY:Float = Math.min(Math.min(tl.y, tr.y), Math.min(bl.y, br.y));
+ var maxX:Float = Math.max(Math.max(tl.x, tr.x), Math.max(bl.x, br.x));
+ var maxY:Float = Math.max(Math.max(tl.y, tr.y), Math.max(bl.y, br.y));
+ xformedBoundingAABB.lowerBound.x = minX;
+ xformedBoundingAABB.lowerBound.y = minY;
+ xformedBoundingAABB.upperBound.x = maxX;
+ xformedBoundingAABB.upperBound.y = maxY;
+ }
+
+ public function set_x(value:Float):Float
+ {
+ position.x = value;
+ return position.x;
+ }
+
+ public function get_x():Float
+ {
+ return position.x;
+ }
+
+ public function get_y():Float
+ {
+ return position.y;
+ }
+
+ public function set_y(value:Float):Float
+ {
+ position.y = value;
+ return position.y;
+ }
+
+ /**
+ * Gets and sets rotation angle in radians
+ */
+ public function get_rotation():Float
+ {
+ return xform.angle;
+ }
+
+ public function set_rotation(value:Float):Float
+ {
+ xform.setAngle(value);
+ recalculateXformedAABB();
+ return xform.angle;
+ }
+
+ /**
+ * Does not modify localPoint
+ * @param localPoint point in local coordinates
+ * @return point in world coordinates
+ */
+ public function localToWorld(localPoint:Vector2D, t:Bool = false):Vector2D
+ {
+ return localPoint.clone().applyXform(xform).add(position);
+ }
+
+ /**
+ * Checks if body is in specified bounds
+ * @param x
+ * @param y
+ * @param width
+ * @param heigth
+ * @return
+ */
+ public function inBounds(x:Float, y:Float, width:Float, heigth:Float):Bool
+ {
+ if (worldAABB.upperBound.x < x)
+ {
+ return false;
+ }
+ if (worldAABB.upperBound.y < y)
+ {
+ return false;
+ }
+ if (worldAABB.lowerBound.x > x + width)
+ {
+ return false;
+ }
+ if (worldAABB.lowerBound.y > y +heigth)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public function reactToCollision(collidingBody:PhysicalBody, selfShape:BaseShape, otherShape:BaseShape):Void
+ {
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/sphaeraGravita/collision/ProjectionResult.hx b/src/sphaeraGravita/collision/ProjectionResult.hx
new file mode 100644
index 0000000..3a06f30
--- /dev/null
+++ b/src/sphaeraGravita/collision/ProjectionResult.hx
@@ -0,0 +1,17 @@
+package sphaeraGravita.collision;
+
+/**
+ * ...
+ * @author Dimonte
+ */
+class ProjectionResult
+{
+ public var min:Float;
+ public var max:Float;
+
+ public function new (min:Float = 0, max:Float = 0)
+ {
+ this.min = min;
+ this.max = max;
+ }
+}
\ No newline at end of file
diff --git a/src/sphaeraGravita/math/RotationMatrix.hx b/src/sphaeraGravita/math/RotationMatrix.hx
new file mode 100644
index 0000000..24e79d1
--- /dev/null
+++ b/src/sphaeraGravita/math/RotationMatrix.hx
@@ -0,0 +1,33 @@
+package sphaeraGravita.math;
+
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+
+class RotationMatrix
+{
+
+ public var sin:Float;
+ public var cos:Float;
+
+ /**
+ * Use this variable to read angle information ONLY! Use setAngle to set angle.
+ */
+ public var angle:Float;
+
+ public function new():Void
+ {
+ setAngle(0);
+ }
+
+ public function setAngle(angle:Float):Void
+ {
+ this.angle = angle;
+ sin = Math.sin(angle);
+ cos = Math.cos(angle);
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/src/sphaeraGravita/math/Vector2D.hx b/src/sphaeraGravita/math/Vector2D.hx
new file mode 100644
index 0000000..cfc8a6b
--- /dev/null
+++ b/src/sphaeraGravita/math/Vector2D.hx
@@ -0,0 +1,117 @@
+package sphaeraGravita.math;
+
+
+/**
+ * ...
+ * @author Dimonte
+ */
+class Vector2D
+{
+
+ public static function dotProduct(vector1:Vector2D, vector2:Vector2D):Float
+ {
+ return vector1.x * vector2.x + vector1.y * vector2.y;
+ }
+
+ public static function project(vector:Vector2D, vectorToProjectOn:Vector2D):Vector2D
+ {
+ var vectorToProjectOnNormal:Vector2D = vectorToProjectOn.clone().normalize();
+ var dp:Float = dotProduct(vector, vectorToProjectOnNormal);
+ return new Vector2D(dp * vectorToProjectOnNormal.x, dp * vectorToProjectOnNormal.y);
+ }
+
+ public var x:Float;
+ public var y:Float;
+
+ public function new(?x:Float=0, ?y:Float=0)
+ {
+ this.x = x;
+ this.y = y;
+ }
+
+ public function getLength():Float
+ {
+ return Math.sqrt(x * x + y * y);
+ }
+
+ public function getLengthSquared():Float
+ {
+ return (x * x + y * y);
+ }
+
+ public function add(vector:Vector2D):Vector2D
+ {
+ x += vector.x;
+ y += vector.y;
+ return this;
+ }
+
+ public function subtract(vector:Vector2D):Vector2D
+ {
+ x -= vector.x;
+ y -= vector.y;
+ return this;
+ }
+
+ public function multiply(multiplier:Float):Vector2D
+ {
+ x *= multiplier;
+ y *= multiplier;
+ return this;
+ }
+
+ public function getNormalLeft():Vector2D
+ {
+ return new Vector2D( y, -x );
+ }
+
+ public function getNormalRight():Vector2D
+ {
+ return new Vector2D( -y, x );
+ }
+
+ public function invert():Vector2D
+ {
+ x = -x;
+ y = -y;
+ return this;
+ }
+
+ public function equals(vector:Vector2D):Bool
+ {
+ return (x == vector.x) && (y == vector.y);
+ }
+
+ public function clone():Vector2D
+ {
+ return new Vector2D(x, y);
+ }
+
+ public function normalize():Vector2D
+ {
+ var length:Float = this.getLength();
+ if ( length == 0 )
+ {
+ return this;
+ } else {
+ x /= length;
+ y /= length;
+ }
+ return this;
+ }
+
+ public function applyXform(xform:RotationMatrix):Vector2D
+ {
+ var newX:Float = x * xform.cos - y * xform.sin;
+ var newY:Float = x * xform.sin + y * xform.cos;
+ x = newX;
+ y = newY;
+ return this;
+ }
+
+ public function toString():String
+ {
+ return "(" + x + "," + y + ")";
+ }
+
+}
\ No newline at end of file
diff --git a/src/sphaeraGravita/shapes/BaseShape.hx b/src/sphaeraGravita/shapes/BaseShape.hx
new file mode 100644
index 0000000..c14decf
--- /dev/null
+++ b/src/sphaeraGravita/shapes/BaseShape.hx
@@ -0,0 +1,33 @@
+package sphaeraGravita.shapes;
+
+import flash.errors.IllegalOperationError;
+import game.CollisionCategory;
+import sphaeraGravita.collision.AABB;
+import sphaeraGravita.collision.CollidingEntity;
+import sphaeraGravita.collision.PhysicalBody;
+import sphaeraGravita.math.Vector2D;
+/**
+ * ...
+ * @author Dimonte
+ */
+class BaseShape extends CollidingEntity
+{
+ public var body:PhysicalBody;
+ public var previous:BaseShape;
+ public var next:BaseShape;
+ public var sensor:Bool;
+ public var name:String;
+ public var type:String;
+
+ public function new(type:String)
+ {
+ this.type = type;
+ }
+
+ public function getBoundingAABB():AABB
+ {
+ throw new IllegalOperationError("Function must be overridden");
+ return new AABB();
+ }
+
+}
\ No newline at end of file
diff --git a/src/sphaeraGravita/shapes/CircleShape.hx b/src/sphaeraGravita/shapes/CircleShape.hx
new file mode 100644
index 0000000..82a800d
--- /dev/null
+++ b/src/sphaeraGravita/shapes/CircleShape.hx
@@ -0,0 +1,28 @@
+package sphaeraGravita.shapes;
+
+import sphaeraGravita.collision.AABB;
+import sphaeraGravita.math.Vector2D;
+
+/**
+ * ...
+ * @author Dimonte
+ */
+class CircleShape extends BaseShape
+{
+ public var radius:Float;
+ public var position:Vector2D;
+
+ public function new(x:Float, y:Float, radius:Float)
+ {
+ super(ShapeType.CIRCLE_SHAPE);
+ position = new Vector2D(x, y);
+ this.radius = radius;
+ }
+
+ override public function getBoundingAABB():AABB
+ {
+ var boundingAABB:AABB = AABB.asMinMax(position.x - radius, position.y - radius, position.x + radius, position.y + radius);
+ return boundingAABB;
+ }
+
+}
\ No newline at end of file
diff --git a/src/sphaeraGravita/shapes/Polygon.hx b/src/sphaeraGravita/shapes/Polygon.hx
new file mode 100644
index 0000000..0b40751
--- /dev/null
+++ b/src/sphaeraGravita/shapes/Polygon.hx
@@ -0,0 +1,95 @@
+package sphaeraGravita.shapes;
+
+import sphaeraGravita.collision.AABB;
+import sphaeraGravita.math.Vector2D;
+/**
+ * ...
+ * @author Dimonte
+ */
+class Polygon extends BaseShape
+{
+ public var vertices:Array;
+ public var normals:Array;
+ private var _worldVerticesCache:Array;
+ public var cacheUpdateRequired:Bool;
+
+ public function new()
+ {
+ super(ShapeType.POLYGON_SHAPE);
+ vertices = new Array();
+ normals = new Array();
+ _worldVerticesCache = new Array();
+ }
+
+ public function setPoly(vertices:Array):Void
+ {
+ this.vertices = vertices;
+ initialize();
+ }
+
+ public function initialize():Void
+ {
+ normals.splice(0, normals.length);
+ for (i in 0...vertices.length - 1)
+ {
+ var edge:Vector2D = vertices[i + 1].clone().subtract(vertices[i]);
+ normals[i] = edge.getNormalLeft().normalize();
+ //trace("vertex " + i, vertices[i]);
+ //_worldVerticesCache[i] = vertices[i].clone().add(position);
+ }
+ normals[vertices.length - 1] = vertices[0].clone().subtract(vertices[vertices.length - 1]).getNormalLeft().normalize();
+ }
+
+ public function getWorldVertex(vertexNum:Int):Vector2D
+ {
+ if (cacheUpdateRequired)
+ {
+ updateWorldVerticesCache();
+ }
+ return _worldVerticesCache[vertexNum];
+ }
+
+ private function updateWorldVerticesCache():Void
+ {
+ for (i in 0...vertices.length)
+ {
+ _worldVerticesCache[i] = body.localToWorld(vertices[i]);
+ }
+ }
+
+ public function getNumVertices():Int
+ {
+ return vertices.length;
+ }
+
+ override public function getBoundingAABB():AABB
+ {
+ var minX:Float = Math.POSITIVE_INFINITY;
+ var minY:Float = Math.POSITIVE_INFINITY;
+ var maxX:Float = Math.NEGATIVE_INFINITY;
+ var maxY:Float = Math.NEGATIVE_INFINITY;
+ var vertice:Vector2D;
+ for (i in 0...vertices.length)
+ {
+ vertice = vertices[i];
+ minX = Math.min(minX, vertice.x);
+ minY = Math.min(minY, vertice.y);
+ maxX = Math.max(maxX, vertice.x);
+ maxY = Math.max(maxY, vertice.y);
+ }
+
+ var boundingAABB:AABB = AABB.asMinMax(minX, minY, maxX, maxY);
+ //trace(boundingAABB);
+ return boundingAABB;
+ }
+
+ public function setAsBox(halfWidth:Float, halfHeight:Float):Void
+ {
+ vertices[0] = new Vector2D( -halfWidth, -halfHeight);
+ vertices[1] = new Vector2D( halfWidth, -halfHeight);
+ vertices[2] = new Vector2D( halfWidth, halfHeight);
+ vertices[3] = new Vector2D( -halfWidth, halfHeight);
+ initialize();
+ }
+
+}
\ No newline at end of file
diff --git a/src/sphaeraGravita/shapes/ShapeType.hx b/src/sphaeraGravita/shapes/ShapeType.hx
new file mode 100644
index 0000000..0b6be64
--- /dev/null
+++ b/src/sphaeraGravita/shapes/ShapeType.hx
@@ -0,0 +1,12 @@
+package sphaeraGravita.shapes;
+
+/**
+ * ...
+ * @author Dimonte
+ */
+class ShapeType
+{
+ public static inline var CIRCLE_SHAPE:String = "circleShape";
+ public static inline var POLYGON_SHAPE:String = "polygonShape";
+
+}
\ No newline at end of file
diff --git a/src/sphaeraGravita/spacePartitioning/GridCell.hx b/src/sphaeraGravita/spacePartitioning/GridCell.hx
new file mode 100644
index 0000000..5940f89
--- /dev/null
+++ b/src/sphaeraGravita/spacePartitioning/GridCell.hx
@@ -0,0 +1,22 @@
+package sphaeraGravita.spacePartitioning;
+
+import dataStructures.DLL;
+/**
+ * ...
+ * @author ...
+ */
+class GridCell
+{
+ public var x:Int;
+ public var y:Int;
+ public var activeObjectList:DLL;
+ public var fixedObjectList:DLL;
+ public var dirty:Bool;
+
+ public function new()
+ {
+ activeObjectList = new DLL();
+ fixedObjectList = new DLL();
+ }
+
+}
\ No newline at end of file
diff --git a/src/sphaeraGravita/spacePartitioning/UniformGrid.hx b/src/sphaeraGravita/spacePartitioning/UniformGrid.hx
new file mode 100644
index 0000000..532eb20
--- /dev/null
+++ b/src/sphaeraGravita/spacePartitioning/UniformGrid.hx
@@ -0,0 +1,165 @@
+package sphaeraGravita.spacePartitioning;
+
+import game.GameEntity;
+import game.Tile;
+import sphaeraGravita.math.Vector2D;
+/**
+ * ...
+ * @author Dmitry Barabanschikov
+ */
+class UniformGrid
+{
+ public static inline var CELL_SIZE:Int = 40; //TODO change to 40, make literal
+
+ public var cells:Array;
+ public var dummy:GridCell;
+ public var dirtyCells:Array;
+ public var height:Int;
+ public var width:Int;
+ public var padding:Int;
+ public var minX:Int;
+ public var maxX:Int;
+ public var paddedWidth:Int;
+ public var minY:Int;
+ public var maxY:Int;
+ public var paddedHeight:Int;
+
+ private var correctedX:Int;
+ private var correctedY:Int;
+
+ public function new()
+ {
+ dummy = new GridCell();
+ cells = new Array();
+ dirtyCells = new Array();
+ }
+
+ /**
+ * Initializes uniform grid
+ * @param width
+ * @param height
+ * @param padding
+ */
+ public function initialize(width:Int, height:Int, padding:Int):Void
+ {
+ dummy = new GridCell();
+ dirtyCells = [];
+
+ this.width = width;
+ this.height = height;
+ this.padding = padding;
+
+ minX = - padding;
+ maxX = width + padding;
+ paddedWidth = width + padding * 2;
+ minY = - padding;
+ maxY = height + padding;
+ paddedHeight = height + padding * 2;
+
+ var totalNumberOfCells:Int = paddedWidth*paddedHeight;
+
+
+ for (i in 0...totalNumberOfCells)
+ {
+ if (cells[i] == null)
+ {
+ cells[i] = new GridCell();
+ }
+ var cell:GridCell = cells[i];
+ cell.activeObjectList.clear();
+ cell.fixedObjectList.clear();
+ cell.x = Std.int(i / paddedHeight) - padding;
+ cell.y = Std.int(i % paddedHeight) - padding;
+ }
+
+ while (cells.length > totalNumberOfCells)
+ {
+ cells.pop();
+ }
+ }
+
+ /**
+ * Cleans all cells containing active objects
+ */
+ public function clean():Void
+ {
+ for (i in 0...dirtyCells.length)
+ {
+ dirtyCells[i].activeObjectList.clear();
+ dirtyCells[i].dirty = false;
+ }
+ while (dirtyCells.length > 0)
+ {
+ dirtyCells.pop();
+ }
+
+ dummy.activeObjectList.clear();
+ }
+
+ /**
+ * Returns cell at (x,y), if out of bounds, returns dummy cell (still usable)
+ * @param x
+ * @param y
+ */
+ public function getCellAt(x:Int, y:Int):GridCell
+ {
+ if (x < minX) { return dummy; }
+ if (x >= maxX) { return dummy; }
+ if (y >= maxY) { return dummy; }
+ if (y < minY) { return dummy; }
+ correctedX = x + padding;
+ correctedY = y + padding;
+ return cells[correctedX * paddedHeight + correctedY];
+ }
+
+ public function placeTile(tile:Tile):Void
+ {
+ //getCellAt(Int(tile.position.x / CELL_SIZE), Int(tile.position.y / CELL_SIZE)).fixedObjectList.append(tile);
+ placeFixedObject(tile);
+ }
+
+ public function placeFixedObject(object:GameEntity):Void
+ {
+ var overlappingCells:Array = getCellsBetweenPoints(object.worldAABB.lowerBound, object.worldAABB.upperBound);
+ object.overlappingCells = overlappingCells;
+ for (i in 0...overlappingCells.length)
+ {
+ overlappingCells[i].fixedObjectList.append(object);
+ }
+ }
+
+ public function placeActiveObject(activeObject:GameEntity):Void
+ {
+ var overlappingCells:Array = getCellsBetweenPoints(activeObject.worldAABB.lowerBound, activeObject.worldAABB.upperBound);
+ activeObject.overlappingCells = overlappingCells;
+ for (i in 0...overlappingCells.length)
+ {
+ overlappingCells[i].activeObjectList.append(activeObject);
+ if (overlappingCells[i].dirty)
+ {
+ continue;
+ } else
+ {
+ dirtyCells.push(overlappingCells[i]);
+ }
+ }
+ }
+
+ public function getCellsBetweenPoints(pointOne:Vector2D, pointTwo:Vector2D):Array
+ {
+ var startX:Int = Std.int(pointOne.x / CELL_SIZE);
+ var startY:Int = Std.int(pointOne.y / CELL_SIZE);
+ var endX:Int = Std.int(pointTwo.x / CELL_SIZE) + 1;
+ var endY:Int = Std.int(pointTwo.y / CELL_SIZE) + 1;
+ var cellArray:Array = [];
+ for (i in startX...endX)
+ {
+ for (j in startY...endY)
+ {
+ cellArray.push(getCellAt(i, j));
+ }
+ }
+ return cellArray;
+ }
+
+}
\ No newline at end of file
diff --git a/src/view/PhysicalWorldView.hx b/src/view/PhysicalWorldView.hx
new file mode 100644
index 0000000..4ad6f39
--- /dev/null
+++ b/src/view/PhysicalWorldView.hx
@@ -0,0 +1,156 @@
+package view;
+
+import assets.GraphicsLibrary;
+import dataStructures.DLL;
+import dataStructures.DLLNode;
+import flash.display.Bitmap;
+import flash.display.BitmapData;
+import flash.geom.Matrix;
+import flash.geom.Point;
+import flash.geom.Rectangle;
+import game.Bullet;
+import game.BulletHit;
+import game.Debries;
+import game.EnemyShip;
+import game.Explosion;
+import game.GameEntity;
+import game.GameStage;
+import game.GameWorld;
+import game.PlayerShip;
+import game.Tile;
+import openfl.Assets;
+import sphaeraGravita.collision.AABB;
+import sphaeraGravita.collision.CollisionResult;
+import sphaeraGravita.collision.PhysicalBody;
+import sphaeraGravita.math.Vector2D;
+import sphaeraGravita.shapes.BaseShape;
+import sphaeraGravita.shapes.CircleShape;
+import sphaeraGravita.shapes.Polygon;
+import sphaeraGravita.shapes.ShapeType;
+import sphaeraGravita.spacePartitioning.GridCell;
+import sphaeraGravita.spacePartitioning.UniformGrid;
+/**
+ * ...
+ * @author Dimonte
+ */
+class PhysicalWorldView extends WorldView
+{
+ public var debugDraw:Bool;
+
+ private var _world:GameWorld;
+ private var _canvas:Bitmap;
+ private var _skyBD:BitmapData;
+ private var _worldDrawMarker:Int;
+ private var screenWidth:Int;
+ private var screenHeight:Int;
+
+ public function new(gameStage:GameStage, screenWidth:Int, screenHeight:Int)
+ {
+ this.screenWidth = screenWidth;
+ this.screenHeight = screenHeight;
+
+ super(gameStage);
+
+ _skyBD = Assets.getBitmapData("assets/general/sky.png");
+ var skyBitmap:Bitmap = new Bitmap(_skyBD);
+ skyBitmap.scaleX = screenWidth / skyBitmap.width;
+ skyBitmap.scaleY = screenHeight / skyBitmap.height;
+ addChild(skyBitmap);
+
+ _world = gameStage.gameWorld;
+ _canvas = new Bitmap(new BitmapData(screenWidth, screenHeight));
+
+ //_canvas.alpha = 0.5;
+ addChild(_canvas);
+
+ createScoreDisplay();
+ }
+
+ override public function update():Void
+ {
+ super.update();
+
+ drawStuff();
+ }
+
+ public function drawStuff():Void
+ {
+ _worldDrawMarker = Std.int(_world.activeZoneStartMarker);
+ _canvas.bitmapData.lock();
+
+ _canvas.bitmapData.fillRect(new Rectangle(0, 0, screenWidth, screenHeight), 0x0);
+
+ drawEntityList(_world.tiles);
+ drawEntityList(_world.playerBullets);
+ if (!_world.player.dead)
+ {
+ drawEntity(_world.player, true);
+ }
+ drawEntityList(_world.enemies);
+ drawEntityList(_world.particles);
+ drawEntityList(_world.enemyBullets);
+
+ _canvas.bitmapData.fillRect(new Rectangle(0, 0, _world.player.healthPoints * (screenWidth/800), 10), 0xFFFF0000);
+
+ _canvas.bitmapData.unlock();
+ }
+
+ private function drawEntityList(list:DLL):Void
+ {
+ var node:DLLNode = list._head;
+ var entity:GameEntity;
+ while (node != null)
+ {
+ entity = cast(node.val, GameEntity);
+ node = node.next;
+ if (entity.dead)
+ {
+ continue;
+ }
+ if (entity.worldAABB.upperBound.x - _worldDrawMarker < 0)
+ {
+ continue;
+ }
+ if (entity.worldAABB.lowerBound.x - _worldDrawMarker > screenWidth)
+ {
+ continue;
+ }
+
+ drawEntity(entity);
+
+ }
+ }
+
+ private function drawEntity(ge:GameEntity, ?debug:Bool = false):Void
+ {
+
+ if (ge == null)
+ {
+ //SOSLog.sosTrace( "ge : " + ge );
+ return;
+ }
+
+ if (ge.graphicsAsset == null)
+ {
+ //SOSLog.sosTrace( "ge.graphicsAsset : " + ge.graphicsAsset );
+ return;
+ }
+
+ var sr:Rectangle = ge.graphicsAsset.frameRectangles[ge.frameRectNum];
+ var dp:Point = new Point(ge.x - _worldDrawMarker, ge.y).add(ge.graphicsAsset.sizeCorrection);
+ var source:BitmapData = ge.graphicsAsset.spriteSheet;
+ if (ge.rotation != 0)
+ {
+ var sourceClip:BitmapData = new BitmapData(Std.int(sr.width), Std.int(sr.height), true, 0x0);
+ sourceClip.copyPixels(source, sr, new Point(0,0));
+ var m:Matrix = new Matrix();
+ m.createBox(1, 1, ge.rotation, dp.x, dp.y);
+ _canvas.bitmapData.draw(sourceClip, m);
+ } else
+ {
+ _canvas.bitmapData.copyPixels(source, sr, dp, null, null, true);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/view/TilesView.hx b/src/view/TilesView.hx
new file mode 100644
index 0000000..7b91d05
--- /dev/null
+++ b/src/view/TilesView.hx
@@ -0,0 +1,151 @@
+package view;
+
+import assets.GraphicsLibrary;
+import dataStructures.DLL;
+import dataStructures.DLLNode;
+import flash.display.Bitmap;
+import flash.display.BitmapData;
+import flash.display.Sprite;
+import game.Bullet;
+import game.BulletHit;
+import game.Debries;
+import game.EnemyShip;
+import game.Explosion;
+import game.GameEntity;
+import game.GameStage;
+import game.GameWorld;
+import game.PlayerShip;
+import game.Tile;
+import openfl.Assets;
+import sphaeraGravita.collision.AABB;
+import sphaeraGravita.collision.CollisionResult;
+import sphaeraGravita.collision.PhysicalBody;
+import sphaeraGravita.math.Vector2D;
+import sphaeraGravita.shapes.BaseShape;
+import sphaeraGravita.shapes.CircleShape;
+import sphaeraGravita.shapes.Polygon;
+import sphaeraGravita.shapes.ShapeType;
+import sphaeraGravita.spacePartitioning.GridCell;
+import sphaeraGravita.spacePartitioning.UniformGrid;
+/**
+ * ...
+ * @author Dimonte
+ */
+class TilesView extends WorldView
+{
+ public var debugDraw:Bool;
+
+ private var _world:GameWorld;
+ private var _skyBD:BitmapData;
+ private var _worldDrawMarker:Int;
+ private var tilesCanvas:Sprite;
+ private var toDraw:Array;
+ private var healthBitmap:Bitmap;
+ private var screenWidth:Int;
+ private var screenHeight:Int;
+
+ public function new(gameStage:GameStage, screenWidth:Int, screenHeight:Int)
+ {
+ super(gameStage);
+
+ this.screenWidth = screenWidth;
+ this.screenHeight = screenHeight;
+
+ _world = gameStage.gameWorld;
+
+ _skyBD = Assets.getBitmapData("assets/general/sky.png");
+ var skyBitmap:Bitmap = new Bitmap(_skyBD);
+ skyBitmap.scaleX = screenWidth / skyBitmap.width;
+ skyBitmap.scaleY = screenHeight / skyBitmap.height;
+ addChild(skyBitmap);
+
+ tilesCanvas = new Sprite();
+ addChild(tilesCanvas);
+
+ healthBitmap = new Bitmap(new BitmapData(1, 1, false, 0xFFFF0000));
+ healthBitmap.scaleY = 10;
+ addChild(healthBitmap);
+
+ toDraw = new Array();
+
+ createScoreDisplay();
+ }
+
+ override public function update():Void
+ {
+ super.update();
+ tilesCanvas.graphics.clear();
+ drawStuff();
+ }
+
+ public function drawStuff():Void
+ {
+ _worldDrawMarker = Std.int(_world.activeZoneStartMarker);
+
+
+ var toDrawLength:Int = 0;
+
+ toDrawLength = addEntityListTiles(_world.tiles, toDraw, toDrawLength);
+ toDrawLength = addEntityListTiles(_world.playerBullets, toDraw, toDrawLength);
+ if (!_world.player.dead)
+ {
+ toDrawLength = drawEntity(_world.player, toDraw, toDrawLength);
+ }
+ toDrawLength = addEntityListTiles(_world.enemies, toDraw, toDrawLength);
+ toDrawLength = addEntityListTiles(_world.particles, toDraw, toDrawLength);
+ toDrawLength = addEntityListTiles(_world.enemyBullets, toDraw, toDrawLength);
+
+ while (toDraw.length > toDrawLength)
+ {
+ toDraw.pop();
+ }
+
+
+ tilesCanvas.graphics.drawTiles(GraphicsLibrary.tilesheet, toDraw);
+
+ //trace( "toDraw : " + toDraw );
+
+ if (healthBitmap.scaleX != _world.player.healthPoints * (screenWidth/800))
+ {
+ healthBitmap.scaleX = _world.player.healthPoints * (screenWidth/800);
+ }
+ }
+
+ private function addEntityListTiles(list:DLL, toDraw:Array, toDrawLength:Int):Int
+ {
+ var node:DLLNode = list._head;
+ var entity:GameEntity;
+ while (node != null)
+ {
+ entity = cast(node.val, GameEntity);
+ node = node.next;
+ if (entity.dead)
+ {
+ continue;
+ }
+ /*if (entity.worldAABB.upperBound.x - _worldDrawMarker < 0)
+ {
+ continue;
+ }
+ if (entity.worldAABB.lowerBound.x - _worldDrawMarker > 800)
+ {
+ continue;
+ }*/
+
+ toDrawLength = drawEntity(entity, toDraw, toDrawLength);
+ }
+ return toDrawLength;
+ }
+
+ private function drawEntity(ge:GameEntity, drawList:Array, toDrawLength:Int):Int
+ {
+ drawList[toDrawLength] = Std.int(ge.x - _worldDrawMarker + ge.graphicsAsset.sizeCorrection.x);
+ toDrawLength++;
+ drawList[toDrawLength] = Std.int(ge.y + ge.graphicsAsset.sizeCorrection.y);
+ toDrawLength++;
+ drawList[toDrawLength] = ge.graphicsAsset.tileSheetFrameID[ge.frameRectNum];
+ toDrawLength++;
+ return toDrawLength;
+ }
+
+}
\ No newline at end of file
diff --git a/src/view/WorldView.hx b/src/view/WorldView.hx
new file mode 100644
index 0000000..5f97a64
--- /dev/null
+++ b/src/view/WorldView.hx
@@ -0,0 +1,50 @@
+package view;
+import flash.display.Sprite;
+import flash.text.TextField;
+import flash.text.TextFieldAutoSize;
+import flash.text.TextFormat;
+import game.GameStage;
+
+/**
+ * ...
+ * @author Dmitriy Barabanschikov
+ */
+
+class WorldView extends Sprite
+{
+ private var scoreTextField:TextField;
+ public var gameStage:GameStage;
+
+ public function new(gameStage:GameStage)
+ {
+ super();
+ this.gameStage = gameStage;
+ }
+
+ public function update():Void
+ {
+ scoreTextField.text = "Score: " + gameStage.gameWorld.score;
+ }
+
+ public function createScoreDisplay():Void
+ {
+ scoreTextField = new TextField();
+ scoreTextField.embedFonts = true;
+ scoreTextField.y = 14;
+ scoreTextField.x = 8;
+ scoreTextField.autoSize = TextFieldAutoSize.LEFT;
+ scoreTextField.mouseEnabled = false;
+
+ var scoreTextFormat:TextFormat = scoreTextField.defaultTextFormat;
+
+ scoreTextFormat.font = FontManager.mainFont.fontName;
+ scoreTextFormat.size = 16;
+ scoreTextFormat.color = 0xFFFFFF;
+ scoreTextFormat.bold = true;
+
+ scoreTextField.defaultTextFormat = scoreTextFormat;
+
+ addChild(scoreTextField);
+ }
+
+}
\ No newline at end of file