game.html 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Raid on river</title>
  6. <style></style>
  7. </head>
  8. <body>
  9. <canvas id="gameCanvas" width="1280" height="720"></canvas>
  10. <script type="text/javascript">
  11. const FPS = 60;
  12. const SCENE_SPEED = 3;
  13. const PLANE_SIZE = 30; //plane height in pixels
  14. const PLANE_ACCELERATION = 2/5; //TODO пока пиксели в секунду
  15. const MISSLE_SPEED = 13; //TODO обдумать на размер сцены
  16. const MISSLE_SIZEY = 20/3*2; //длина снаряда
  17. const MISSLE_SIZEX = 5; //ширина снаряда
  18. const SHOOT_COOLDOWN = 3/8; //в секундах
  19. const SHIPS_COUNT = 3; //начальное кол-во кораблей
  20. const SHIP_SIZEY = 25; //высота корабля
  21. const SHIP_SIZEX = 100; //ширина корабля
  22. const CONTROL_LEFT = 90; //90 - Z
  23. const CONTROL_RIGHT = 88; //88 - X
  24. const CONTROL_FIRE = 190; //190 - ,
  25. const SHOW_BOUNDING = true;
  26. /** @type {HTMLCanvasElement} */
  27. var canv = document.getElementById("gameCanvas");
  28. var ctx = canv.getContext("2d");
  29. var score = 0;
  30. var scene = { //хранит бэкраунд
  31. boundaries: []
  32. }
  33. addBoundaries();
  34. var plane = {
  35. x: canv.width / 2,
  36. y: canv.height / 2 + 100,
  37. r: PLANE_SIZE / 2,
  38. a: 90 / 180 * Math.PI,
  39. acceleration: {
  40. posx: false,
  41. negx: false,
  42. },
  43. speedx: 0,
  44. reload: false,
  45. reloadtime: 0,
  46. missles: [],
  47. collision: {
  48. x: 0,
  49. y: 0,
  50. w: PLANE_SIZE,
  51. h: PLANE_SIZE,
  52. },
  53. }
  54. var ships = [];
  55. createShip();
  56. //set up event handler
  57. document.addEventListener("keydown", keyDown);
  58. document.addEventListener("keyup", keyUp);
  59. //game loop
  60. setInterval(update, 1000 / FPS);
  61. function addBoundaries(){
  62. scene.boundaries.push(addBounadry(0, 4 * 720, 1280 / 4));
  63. scene.boundaries.push(addBounadry(1280 - 1280 / 4, 4 * 720, 1280 / 4));
  64. scene.boundaries[0].collision.y += 720;
  65. scene.boundaries[1].collision.y += 720;
  66. //addBounadry();
  67. //addBounadry();
  68. }
  69. function addBounadry(bx,by,bw){
  70. var boundary = {
  71. replaced: false,
  72. collision: {
  73. x: bx,
  74. y: -by,
  75. w: bw,
  76. h: by,
  77. }
  78. }
  79. return boundary;
  80. }
  81. function createShip() {
  82. ships = [];
  83. for (var i = 0; i < SHIPS_COUNT; i++) {
  84. ships.push(newShip());
  85. }
  86. }
  87. //key events
  88. function keyDown(/** @type {KeyboardEvent} */ ev) {
  89. switch (ev.keyCode) {
  90. case CONTROL_LEFT: //Move to the left
  91. plane.acceleration.negx = true;
  92. break;
  93. case CONTROL_RIGHT: //Move to the right
  94. plane.acceleration.posx = true;
  95. break;
  96. case CONTROL_FIRE: //Fire the missle
  97. shootMissle();
  98. break;
  99. }
  100. }
  101. function keyUp(/** @type {KeyboardEvent} */ ev) {
  102. switch (ev.keyCode) {
  103. case CONTROL_LEFT: //Move to the left
  104. plane.acceleration.negx = false;
  105. break;
  106. case CONTROL_RIGHT: //Move to the right
  107. plane.acceleration.posx = false;
  108. break;
  109. case CONTROL_FIRE: //Fire the missle
  110. //plane.reload = false;
  111. break;
  112. }
  113. }
  114. function newShip(x) {
  115. let direction
  116. if (Math.floor(Math.random()*2) == 0) {
  117. direction = -1;
  118. } else {
  119. direction = 1;
  120. }
  121. var ship = {
  122. x: 0,
  123. y: 0 - SHIP_SIZEY,
  124. a: direction,
  125. collision: {
  126. x: 0,
  127. y: 0,
  128. w: SHIP_SIZEX,
  129. h: SHIP_SIZEY,
  130. },
  131. }
  132. var shipPosGeneration = true;
  133. while (shipPosGeneration == true) {
  134. ship.x = Math.floor(Math.random()*1280);
  135. ship.collision.x = ship.x - SHIP_SIZEX / 2;
  136. shipPosGeneration = false;
  137. for (var i = 0; i < scene.boundaries.length; i++) {
  138. if (checkRectangularCollision(ship.collision, scene.boundaries[i].collision) ) {
  139. shipPosGeneration = true;
  140. }
  141. }
  142. for (var i = 0; i < ships.length; i++)
  143. if (checkRectangularCollision(ship.collision, ships[i].collision) ) {
  144. shipPosGeneration = true;
  145. }
  146. }
  147. console.log(ship.x);
  148. return ship;
  149. }
  150. function shootMissle() {
  151. if (!plane.reload) {
  152. plane.missles.push({
  153. x: plane.x + 4 / 3 * plane.r * Math.cos(plane.a),
  154. y: plane.y - 4 / 3 * plane.r * Math.sin(plane.a),
  155. collision: {
  156. x: plane.x + 4 / 3 * plane.r * Math.cos(plane.a) - MISSLE_SIZEX / 2,
  157. y: plane.y - 4 / 3 * plane.r * Math.sin(plane.a),
  158. w: MISSLE_SIZEX,
  159. h: MISSLE_SIZEY,
  160. },
  161. })
  162. console.log("*shoot*");
  163. plane.reloadtime = SHOOT_COOLDOWN * FPS;
  164. plane.reload = true;
  165. }
  166. }
  167. function checkRectangularCollision(a, b){ //проверка коллизии 2х прямоугольных объекттов
  168. if (a.x < b.x + b.w &&
  169. a.x + a.w > b.x &&
  170. a.y < b.y + b.h &&
  171. a.h + a.y > b.y) {
  172. console.log("collision detected");
  173. return true
  174. }
  175. else {
  176. //console.log("no collision");
  177. return false;
  178. }
  179. }
  180. function checkPlaneSceneCollision(x,y,c) { //проверка коллизии самолёта с сценой
  181. var collsion = {
  182. x: x + 4 / 3 * plane.r * Math.cos(plane.a) - PLANE_SIZE / 2,
  183. y: y - 4 / 3 * plane.r * Math.sin(plane.a),
  184. w: PLANE_SIZE,
  185. h: PLANE_SIZE,
  186. }
  187. //plane.collision.x =
  188. //plane.collision.y = plane.y - 4 / 3 * plane.r * Math.sin(plane.a)
  189. var problem = false;
  190. if (collsion.x < c.x + c.w &&
  191. collsion.x + collsion.w > c.x &&
  192. collsion.y < c.y + c.h &&
  193. collsion.h + collsion.y > c.y) {
  194. problem = true;
  195. }
  196. if (problem) {
  197. if (collsion.x < (c.x + c.w) && collsion.x > c.x) { //левостороняя коллизия
  198. return c.x + c.w + PLANE_SIZE/2;
  199. }
  200. if (collsion.x + collsion.w > c.x && collsion.x + collsion.w < c.x + c.w) { //правостороняя коллизия
  201. return c.x - plane.r;
  202. }
  203. }
  204. else {
  205. return 0;
  206. }
  207. return 1280/2;
  208. }
  209. function drawCollision(a, color) { //Рисует коллизию объекта
  210. ctx.strokeStyle = color;
  211. ctx.strokeRect(a.x, a.y, a.w, a.h);
  212. }
  213. function update() {
  214. //draw scene
  215. ctx.fillStyle = "black";
  216. ctx.fillRect(0,0, canv.width, canv.height)
  217. //отрисовка бэкграунда
  218. for (var i = 0; i < scene.boundaries.length; i++) {
  219. if (SHOW_BOUNDING) {
  220. drawCollision(scene.boundaries[i].collision,"blue");
  221. }
  222. }
  223. //проверка коллизии
  224. //коллизия кораблей с самолётом
  225. for (var i = 0; i < ships.length; i++){
  226. if (checkRectangularCollision(ships[i].collision, plane.collision)) {
  227. console.log("Plane collading with ship no. " + i )
  228. }
  229. }
  230. //коллизия снаряда с кораблями
  231. for (var i = ships.length - 1; i >= 0; i--){
  232. for (var j = plane.missles.length - 1; j >= 0; j--) {
  233. if (checkRectangularCollision(ships[i].collision, plane.missles[j].collision)) {
  234. console.log("Missle no. " + j + " collading with ship no. " + i )
  235. plane.missles.splice(j,1);
  236. ships.splice(i,1);
  237. score += 30;
  238. console.log("New score: " + score);
  239. ships.push(newShip());
  240. }
  241. }
  242. }
  243. //move scene
  244. //движение бэкграунда
  245. for (var i = scene.boundaries.length - 1; i >= 0; i--) {
  246. //scene.boundaries[i]
  247. if (scene.boundaries[i].collision.y > 720 ) { //удаление ушедших границ
  248. scene.boundaries.splice(i,1);
  249. continue;
  250. }
  251. if (scene.boundaries[i].collision.y > 0 && !scene.boundaries[i].replaced) {
  252. scene.boundaries.push(addBounadry(scene.boundaries[i].collision.x, 4 * 720, scene.boundaries[i].collision.w));
  253. scene.boundaries[scene.boundaries.length - 1].collision.y =
  254. scene.boundaries[i].collision.y - scene.boundaries[scene.boundaries.length - 1].collision.h + SCENE_SPEED;
  255. scene.boundaries[i].replaced = true;
  256. }
  257. scene.boundaries[i].collision.y += SCENE_SPEED; //TODO двигать нет только коллизию
  258. //console.log(scene.boundaries[i].collision.y);
  259. }
  260. //двигаем объекты
  261. //двигаем корабли
  262. for (var i = ships.length - 1; i >= 0 ; i--){
  263. if (ships[i].y > 720 + SHIP_SIZEY / 2) { //удаление снарядов за экраном
  264. ships.splice(i,1);
  265. ships.push(newShip());
  266. continue;
  267. }
  268. ships[i].y += SCENE_SPEED;
  269. ships[i].collision.x = ships[i].x - SHIP_SIZEX / 2;
  270. ships[i].collision.y = ships[i].y - SHIP_SIZEY / 2;
  271. //console.log(ships[i].collision.w);
  272. }
  273. //рисуем корабли
  274. for (var i = 0; i < ships.length ; i++){
  275. ctx.beginPath();
  276. ctx.moveTo( //корабля
  277. ships[i].x + ships[i].a * (SHIP_SIZEX / 6),
  278. ships[i].y - SHIP_SIZEY / 2
  279. )
  280. ctx.lineTo(
  281. ships[i].x - ships[i].a * (SHIP_SIZEX / 20 ) + ships[i].a * (SHIP_SIZEX / 6),
  282. ships[i].y - SHIP_SIZEY / 2
  283. )
  284. ctx.lineTo(
  285. ships[i].x - ships[i].a * (SHIP_SIZEX / 13) + ships[i].a * (SHIP_SIZEX / 6),
  286. ships[i].y - SHIP_SIZEY / 4
  287. )
  288. ctx.lineTo(
  289. ships[i].x - ships[i].a * (SHIP_SIZEX / 5) + ships[i].a * (SHIP_SIZEX / 6),
  290. ships[i].y - SHIP_SIZEY / 4
  291. )
  292. ctx.lineTo(
  293. ships[i].x - ships[i].a * (SHIP_SIZEX / 3) + ships[i].a * (SHIP_SIZEX / 6),
  294. ships[i].y + SHIP_SIZEY / 6
  295. )
  296. ctx.lineTo(
  297. ships[i].x - ships[i].a * SHIP_SIZEX / 2,
  298. ships[i].y + SHIP_SIZEY / 6
  299. )
  300. ctx.lineTo(
  301. ships[i].x - ships[i].a * SHIP_SIZEX * 2 / 7,
  302. ships[i].y + SHIP_SIZEY / 2
  303. )
  304. ctx.lineTo(
  305. ships[i].x + ships[i].a * SHIP_SIZEX / 3,
  306. ships[i].y + SHIP_SIZEY / 2
  307. )
  308. ctx.lineTo(
  309. ships[i].x + ships[i].a * SHIP_SIZEX / 2 ,
  310. ships[i].y + SHIP_SIZEY / 6
  311. )
  312. ctx.lineTo(
  313. ships[i].x + ships[i].a * SHIP_SIZEX / 2 - ships[i].a * SHIP_SIZEX / 10 ,
  314. ships[i].y + SHIP_SIZEY / 6
  315. )
  316. ctx.lineTo(
  317. ships[i].x + ships[i].a * (SHIP_SIZEX / 6),
  318. ships[i].y - SHIP_SIZEY / 4
  319. )
  320. ctx.closePath();
  321. ctx.fillStyle = "red";
  322. ctx.fill();
  323. if (SHOW_BOUNDING) {
  324. ctx.strokeStyle = "lime";
  325. ctx.strokeRect(
  326. ships[i].x - SHIP_SIZEX / 2,
  327. ships[i].y - SHIP_SIZEY / 2,
  328. SHIP_SIZEX,
  329. SHIP_SIZEY
  330. )
  331. }
  332. }
  333. //draw plane
  334. //ctx.lineWidth = PLANE_SIZE / 20;
  335. ctx.beginPath();
  336. ctx.moveTo( //nose of the plane
  337. plane.x + 4 / 3 * plane.r * Math.cos(plane.a),
  338. plane.y - 4 / 3 * plane.r * Math.sin(plane.a)
  339. );
  340. ctx.lineTo( //rear left of the plane
  341. plane.x - plane.r * (2 / 3 * Math.cos(plane.a) + Math.sin(plane.a)),
  342. plane.y + plane.r * (2 / 3 * Math.sin(plane.a) - Math.cos(plane.a))
  343. );
  344. ctx.lineTo( //rear right of the plane
  345. plane.x - plane.r * (2 / 3 * Math.cos(plane.a) - Math.sin(plane.a)),
  346. plane.y + plane.r * (2 / 3 * Math.sin(plane.a) + Math.cos(plane.a))
  347. );
  348. ctx.closePath();
  349. ctx.fillStyle = "yellow";
  350. ctx.fill();
  351. //ctx.strokeStyle = "yellow";
  352. //ctx.stroke();
  353. if (SHOW_BOUNDING) {
  354. //console.log(plane.collision.x);
  355. drawCollision(plane.collision,"blue");
  356. }
  357. //Рисуем снаряды
  358. for (var i = 0; i < plane.missles.length; i++) {
  359. ctx.beginPath();
  360. ctx.moveTo( //верхушка снаряда
  361. plane.missles[i].x,
  362. plane.missles[i].y
  363. )
  364. ctx.lineTo( //левый верхний угол снаряда
  365. plane.missles[i].x - MISSLE_SIZEX / 2,
  366. plane.missles[i].y + MISSLE_SIZEX / 2
  367. )
  368. ctx.lineTo( //левый нижний угол снаряда
  369. plane.missles[i].x - MISSLE_SIZEX / 2,
  370. plane.missles[i].y + MISSLE_SIZEY
  371. )
  372. ctx.lineTo( //правый нижний угол снаряда
  373. plane.missles[i].x + MISSLE_SIZEX / 2,
  374. plane.missles[i].y + MISSLE_SIZEY
  375. )
  376. ctx.lineTo( //правый верхний угол снаряда
  377. plane.missles[i].x + MISSLE_SIZEX / 2,
  378. plane.missles[i].y + MISSLE_SIZEX / 2
  379. )
  380. ctx.closePath();
  381. //ctx.strokeStyle = "cyan";
  382. ctx.fillStyle = "cyan";
  383. ctx.fill();
  384. if (SHOW_BOUNDING) {
  385. drawCollision(plane.missles[i].collision,"pink");
  386. }
  387. }
  388. //update acceleration
  389. if (plane.acceleration.posx ^ plane.acceleration.negx){
  390. //console.log("acceleration calc")
  391. if (plane.acceleration.posx){
  392. if (plane.speedx > 0) plane.speedx = 0 //исключение "пьяного" замедления
  393. plane.speedx -= PLANE_ACCELERATION;
  394. }
  395. if (plane.acceleration.negx) {
  396. if (plane.speedx < 0) plane.speedx = 0 //исключение "пьяного" замедления
  397. plane.speedx += PLANE_ACCELERATION;
  398. }
  399. } else {
  400. plane.speedx = 0;
  401. }
  402. //move the plane
  403. //TODO размер сцены
  404. rightBorder = 1280;
  405. leftBorder = 0;
  406. for (var i = 0; i < scene.boundaries.length; i++) {
  407. var newPlaneX = checkPlaneSceneCollision(plane.x - plane.speedx, plane.y,scene.boundaries[i].collision)
  408. if (newPlaneX != 0){
  409. plane.speedx = 0;
  410. plane.x = newPlaneX;
  411. //plane.acceleration.negx = false;
  412. //plane.acceleration.posx = false;
  413. console.log("collsion with boundary no." + i)
  414. }
  415. }
  416. plane.x -= plane.speedx;
  417. /*
  418. if ((plane.x - plane.speedx) <= (rightBorder - plane.r) && (plane.x - plane.speedx) >= (0 + plane.r))
  419. { plane.x -= plane.speedx;
  420. } else {
  421. if ((plane.x - plane.speedx) > (rightBorder - plane.r)){
  422. plane.x =(rightBorder - plane.r);
  423. } else {
  424. if ((plane.x - plane.speedx) < (leftBorder + plane.r)) {
  425. plane.x = (leftBorder + plane.r);
  426. }
  427. }
  428. }
  429. */
  430. plane.collision.x = plane.x + 4 / 3 * plane.r * Math.cos(plane.a) - PLANE_SIZE / 2;
  431. plane.collision.y = plane.y - 4 / 3 * plane.r * Math.sin(plane.a)
  432. //двигаем снаряды
  433. for (var i = plane.missles.length - 1; i >= 0 ; i--) {
  434. if (plane.missles[i].y < 0 - MISSLE_SIZEY) { //удаление снарядов за экраном
  435. plane.missles.splice(i,1);
  436. continue;
  437. }
  438. plane.missles[i].y -= MISSLE_SPEED;
  439. plane.missles[i].collision.x = plane.missles[i].x - MISSLE_SIZEX / 2;
  440. plane.missles[i].collision.y = plane.missles[i].y;
  441. }
  442. if (plane.reload) { //перезарядка
  443. if (plane.reloadtime <= 0){
  444. console.log("reloaded");
  445. plane.reload = false;
  446. } else {
  447. plane.reloadtime--;
  448. }
  449. }
  450. }
  451. </script>
  452. </body>
  453. </html>