elsfk.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. <template>
  2. <div>
  3. <canvas :id="id" width="320" height="620" tabindex="0"/>
  4. </div>
  5. </template>
  6. <script lang="ts">
  7. import { Component, Vue } from "vue-property-decorator";
  8. import { v1 as uuid } from "uuid";
  9. import { SCanvasView, SColor, SPainter } from "@persagy-web/draw/lib";
  10. class TestView extends SCanvasView {
  11. /** 背景表示数组 */
  12. map: number[][] = [];
  13. /** 方块类型索引 */
  14. fkType: number = Number(Math.floor(Math.random() * 7)); // 0-6
  15. /** 方块变形索引 */
  16. dir: number = Number(Math.floor((Math.random() * 4))); // 0-3
  17. /** 所有方块集合 */
  18. fk: number[][][] = [
  19. [
  20. [0, 0, 0, 0],
  21. [0, 1, 1, 0],
  22. [0, 1, 1, 0],
  23. [0, 0, 0, 0],
  24. ],
  25. [
  26. [0, 0, 0, 0],
  27. [0, 1, 1, 0],
  28. [0, 1, 1, 0],
  29. [0, 0, 0, 0],
  30. ],
  31. [
  32. [0, 0, 0, 0],
  33. [0, 1, 1, 0],
  34. [0, 1, 1, 0],
  35. [0, 0, 0, 0],
  36. ],
  37. [
  38. [0, 0, 0, 0],
  39. [0, 1, 1, 0],
  40. [0, 1, 1, 0],
  41. [0, 0, 0, 0],
  42. ],
  43. [
  44. [0, 1, 0, 0],
  45. [0, 1, 0, 0],
  46. [0, 1, 0, 0],
  47. [0, 1, 0, 0],
  48. ],
  49. [
  50. [0, 0, 0, 0],
  51. [1, 1, 1, 1],
  52. [0, 0, 0, 0],
  53. [0, 0, 0, 0],
  54. ],
  55. [
  56. [0, 0, 1, 0],
  57. [0, 0, 1, 0],
  58. [0, 0, 1, 0],
  59. [0, 0, 1, 0],
  60. ],
  61. [
  62. [0, 0, 0, 0],
  63. [0, 0, 0, 0],
  64. [1, 1, 1, 1],
  65. [0, 0, 0, 0],
  66. ],
  67. [
  68. [0, 0, 0, 0],
  69. [0, 1, 1, 0],
  70. [1, 1, 0, 0],
  71. [0, 0, 0, 0],
  72. ],
  73. [
  74. [0, 1, 0, 0],
  75. [0, 1, 1, 0],
  76. [0, 0, 1, 0],
  77. [0, 0, 0, 0],
  78. ],
  79. [
  80. [0, 0, 0, 0],
  81. [0, 0, 1, 1],
  82. [0, 1, 1, 0],
  83. [0, 0, 0, 0],
  84. ],
  85. [
  86. [0, 0, 0, 0],
  87. [0, 1, 0, 0],
  88. [0, 1, 1, 0],
  89. [0, 0, 1, 0],
  90. ],
  91. [
  92. [0, 0, 0, 0],
  93. [0, 1, 1, 0],
  94. [0, 0, 1, 1],
  95. [0, 0, 0, 0],
  96. ],
  97. [
  98. [0, 0, 0, 0],
  99. [0, 0, 1, 0],
  100. [0, 1, 1, 0],
  101. [0, 1, 0, 0],
  102. ],
  103. [
  104. [0, 0, 0, 0],
  105. [1, 1, 0, 0],
  106. [0, 1, 1, 0],
  107. [0, 0, 0, 0],
  108. ],
  109. [
  110. [0, 0, 1, 0],
  111. [0, 1, 1, 0],
  112. [0, 1, 0, 0],
  113. [0, 0, 0, 0],
  114. ],
  115. [
  116. [0, 0, 0, 0],
  117. [0, 1, 1, 0],
  118. [0, 0, 1, 0],
  119. [0, 0, 1, 0],
  120. ],
  121. [
  122. [0, 0, 0, 0],
  123. [0, 0, 1, 0],
  124. [1, 1, 1, 0],
  125. [0, 0, 0, 0],
  126. ],
  127. [
  128. [0, 1, 0, 0],
  129. [0, 1, 0, 0],
  130. [0, 1, 1, 0],
  131. [0, 0, 0, 0],
  132. ],
  133. [
  134. [0, 0, 0, 0],
  135. [0, 1, 1, 1],
  136. [0, 1, 0, 0],
  137. [0, 0, 0, 0],
  138. ],
  139. [
  140. [0, 0, 0, 0],
  141. [0, 1, 1, 0],
  142. [0, 1, 0, 0],
  143. [0, 1, 0, 0],
  144. ],
  145. [
  146. [0, 0, 0, 0],
  147. [1, 1, 1, 0],
  148. [0, 0, 1, 0],
  149. [0, 0, 0, 0],
  150. ],
  151. [
  152. [0, 0, 1, 0],
  153. [0, 0, 1, 0],
  154. [0, 1, 1, 0],
  155. [0, 0, 0, 0],
  156. ],
  157. [
  158. [0, 0, 0, 0],
  159. [0, 1, 0, 0],
  160. [0, 1, 1, 1],
  161. [0, 0, 0, 0],
  162. ],
  163. [
  164. [0, 0, 0, 0],
  165. [0, 0, 1, 0],
  166. [0, 1, 1, 1],
  167. [0, 0, 0, 0],
  168. ],
  169. [
  170. [0, 0, 0, 0],
  171. [0, 1, 0, 0],
  172. [0, 1, 1, 0],
  173. [0, 1, 0, 0],
  174. ],
  175. [
  176. [0, 0, 0, 0],
  177. [1, 1, 1, 0],
  178. [0, 1, 0, 0],
  179. [0, 0, 0, 0],
  180. ],
  181. [
  182. [0, 0, 1, 0],
  183. [0, 1, 1, 0],
  184. [0, 0, 1, 0],
  185. [0, 0, 0, 0],
  186. ]
  187. ];
  188. /** 方块初始位置x坐标 */
  189. x = 5;
  190. /** 方块初始位置y坐标 */
  191. y = 0;
  192. /** 记录上次刷新时间 */
  193. t = Date.now();
  194. /**
  195. * 构造函数
  196. * @param id canvas DOM id
  197. */
  198. constructor(id: string) {
  199. super(id);
  200. this.initMap();
  201. }
  202. /**
  203. * 键盘按下事件
  204. * @param event 事件对象
  205. */
  206. onKeyDown(event: KeyboardEvent): void {
  207. //按键判断
  208. if (event.code == "KeyW") {
  209. //变形后是否碰撞
  210. if (!this.isPz(this.x, this.y, (this.dir + 1) % 4)) {
  211. this.dir = (this.dir + 1) % 4;
  212. }
  213. } else if (event.code == "KeyA") {
  214. //左移后是否碰撞
  215. if (!this.isPz(this.x - 1, this.y, this.dir)) {
  216. this.x--;
  217. }
  218. } else if (event.code == "KeyD") {
  219. //检查右移后是否碰撞
  220. if (!this.isPz(this.x + 1, this.y, this.dir)) {
  221. this.x++;
  222. }
  223. } else if (event.code == "KeyS") {
  224. //检查下移后是否碰撞
  225. if (!this.isPz(this.x, this.y + 1, this.dir)) {
  226. this.y++;
  227. } else {
  228. this.fullMap();
  229. this.xc();
  230. }
  231. }
  232. this.update();
  233. }
  234. /**
  235. * Item 绘制操作
  236. *
  237. * @param painter 绘制对象
  238. */
  239. onDraw(painter: SPainter): void {
  240. //清除画布
  241. painter.clearRect(0, 0, this.width, this.height);
  242. //绘制操作相关命令
  243. painter.pen.color = SColor.Transparent;
  244. painter.brush.color = SColor.Red;
  245. this.drawMap(painter);
  246. this.drawFk(painter);
  247. if (Date.now() - this.t > 500) {
  248. if (!this.isPz(this.x, this.y + 1, this.dir)) {
  249. this.y++;
  250. } else {
  251. this.fullMap();
  252. this.xc();
  253. }
  254. this.t = Date.now();
  255. }
  256. this.update();
  257. }
  258. /**
  259. *初始化背景
  260. */
  261. private initMap(): void {
  262. this.map = [];
  263. for (let row = 0; row < 22; row++) {
  264. const m1: number[] = []
  265. for (let col = 0; col < 14; col++) {
  266. if (row > 19 || col < 2 || col > 11) {
  267. m1.push(2);
  268. } else {
  269. m1.push(0);
  270. }
  271. }
  272. this.map.push(m1);
  273. }
  274. }
  275. /**
  276. * 绘制背景
  277. *
  278. * @param painter 绘制对象
  279. */
  280. private drawMap(painter: SPainter): void {
  281. for (let row = 0; row < 22; row++) {
  282. for (let col = 0; col < 14; col++) {
  283. const x = col * 30 + 11 - 60;
  284. const y = row * 30 + 11;
  285. //赋到背景
  286. if (this.map[row][col] == 1) {
  287. painter.drawRect(col * 30 + 11 - 60, row * 30 + 11, 28, 28);
  288. }
  289. //底加一行
  290. if (this.map[row][col] == 2) {
  291. painter.drawRect(col * 30 + 11 - 60, row * 30 + 11, 28, 28);
  292. }
  293. }
  294. }
  295. }
  296. /**
  297. * 绘制实体图形
  298. *
  299. * @param painter 绘制对象
  300. */
  301. private drawFk(painter: SPainter): void {
  302. for (let row = 0; row < 4; row++) {
  303. for (let col = 0; col < 4; col++) {
  304. if (this.fk[this.fkType * 4 + this.dir][row][col] == 1) {
  305. painter.drawRect((col + this.x) * 30 + 11 - 60, (row + this.y) * 30 + 11, 28, 28);
  306. }
  307. }
  308. }
  309. }
  310. /**
  311. * 是否碰撞
  312. *
  313. * @param x x坐标
  314. * @param y y坐标
  315. * @param dir 方块变形索引
  316. * @return 是否碰撞
  317. */
  318. private isPz(x: number, y: number, dir: number): boolean {
  319. for (let row = 0; row < 4; row++) {
  320. for (let col = 0; col < 4; col++) {
  321. if (this.fk[this.fkType * 4 + dir][row][col] == 1 && this.map[y + row][x + col] != 0) {
  322. return true;
  323. }
  324. }
  325. }
  326. return false;
  327. }
  328. /**
  329. * 将方块合到背景中
  330. */
  331. private fullMap() {
  332. for (let row = 0; row < 4; row++) {
  333. for (let col = 0; col < 4; col++) {
  334. if (this.fk[this.fkType * 4 + this.dir][row][col] == 1) {
  335. this.map[this.y + row][this.x + col] = 1;
  336. }
  337. }
  338. }
  339. this.x = 5;
  340. this.y = 0;
  341. this.fkType = Number((Math.random() * 6).toFixed());
  342. this.dir = Number((Math.random() * 2).toFixed());
  343. }
  344. /**
  345. * 消除满行
  346. */
  347. private xc(): void {
  348. for (let row = 0; row < 20; row++) {
  349. let flag = true;
  350. for (let col = 0; col < 14; col++) {
  351. if (this.map[row][col] == 0) {
  352. flag = false;
  353. break;
  354. }
  355. }
  356. if (flag) {
  357. this.map.splice(row, 1);
  358. this.map.unshift()
  359. this.map.unshift(this.randomRow(10, 0))
  360. // this.map.unshift([2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2]);
  361. // row--;
  362. }
  363. }
  364. }
  365. /**
  366. * 随机数组生成
  367. *
  368. * @return 数组
  369. */
  370. private randomRow(len: number = 10, num: number = 2): number[] {
  371. let array = new Array(len + 4).fill(2);
  372. for (let i = 2; i < array.length - 2; i++) {
  373. array[i] = Math.floor(num * Math.random())
  374. }
  375. return array
  376. }
  377. }
  378. @Component
  379. export default class ElsfkCanvas extends Vue {
  380. id: string = uuid();
  381. mounted(): void {
  382. new TestView(this.id);
  383. }
  384. }
  385. </script>