123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560 |
- <template>
- <div style="position: relative;">
- <canvas id="canvas" width="400" height="400" style="border: 1px #ccc solid;background: #bbada0" tabindex="0"/>
- <div style="position: absolute;top: 0;left: 450px;">
- <p>分数:{{ view ? view.score : 0 }}</p>
- <el-button @click="reset" type="primary">重新开始</el-button>
- <p>W:上移</p>
- <p>S:下移</p>
- <p>A:左移</p>
- <p>D:右移</p>
- </div>
- </div>
- </template>
- <script lang="ts">
- import {Component, Vue} from "vue-property-decorator"
- import {SCanvasView, SColor, SPainter, STextAlign, STextBaseLine} from "@persagy-web/draw/lib";
- class GameView extends SCanvasView {
-
- gridMap = Array(4).fill(null).map(() => Array(4).fill(0))
-
- gameOver: boolean = false
-
- score = 0;
-
-
-
-
-
- color = {
- 0: {
- font: "#ffffffff",
- background: "#eee4da59"
- },
- 2: {
- font: "#776e65",
- background: "#eee4da"
- },
- 4: {
- font: "#776e65",
- background: "#ede0c8"
- },
- 8: {
- font: "#f9f6f2",
- background: "#f2b179"
- },
- 16: {
- font: "#f9f6f2",
- background: "#f59563"
- },
- 32: {
- font: "#f9f6f2",
- background: "#f67c5f"
- },
- 64: {
- font: "#f9f6f2",
- background: "#f65e3b"
- },
- 128: {
- font: "#f9f6f2",
- background: "#edcf72"
- },
- 256: {
- font: "#f9f6f2",
- background: "#edcc61"
- },
- 512: {
- font: "#f9f6f2",
- background: "#edc850"
- },
- 1024: {
- font: "#f9f6f2",
- background: "#edc53f"
- },
- 2048: {
- font: "#f9f6f2",
- background: "#edc22e"
- },
- };
-
- constructor(id: string) {
- super(id);
-
- this.init()
- }
-
- init(): void {
-
- for (let r = 0; r < 4; r++) {
-
- for (let c = 0; c < 4; c++) {
- this.gridMap[r][c] = 0
- }
- }
-
- this.gridMap[Math.floor(Math.random() * 4)][Math.floor(Math.random() * 4)] = 2
- this.gridMap[Math.floor(Math.random() * 4)][Math.floor(Math.random() * 4)] = 2
-
- this.score = 0
-
- this.gameOver = false
- }
-
- onKeyDown(event: KeyboardEvent): void {
- if (this.gameOver) {
- return;
- }
-
- switch (event.code) {
- case "KeyW":
- case "ArrowUp":
-
- this.moveUp();
- break;
- case "KeyA":
- case "ArrowLeft":
-
- this.moveLeft();
- break;
- case "KeyD":
- case "ArrowRight":
- this.moveRight();
-
- break;
-
- case "KeyS":
- case "ArrowDown":
-
- this.moveDown();
- break;
- default :
-
- }
-
- this.update();
- }
-
- moveUp(): void {
-
- let moved = false
-
- for (let i = 0; i < 4; i++) {
-
- const numArr = Array(4)
-
- for (let j = 0; j < 4; j++) {
-
- numArr[j] = this.gridMap[j][i]
- }
-
- if (this.moveNum(numArr)) {
- moved = true;
-
- for (let j = 0; j < 4; j++) {
-
- this.gridMap[j][i] = numArr[j]
- }
- }
- }
-
- if (moved) {
-
- const indexArr = []
-
- for (let i = 0; i < 4; i++) {
-
- if (this.gridMap[3][i] == 0) {
-
- indexArr.push(i)
- }
- }
-
- const index = this.newIndex(indexArr);
- if (index >= 0) {
- this.gridMap[3][index] = this.newNum()
- }
- }
-
- this.gameOver = this.checkGameover()
- }
-
- moveDown(): void {
-
- let moved = false;
-
- for (let i = 0; i < 4; i++) {
-
- const numArr = Array(4);
-
- for (let j = 0; j < 4; j++) {
-
- numArr[j] = this.gridMap[3 - j][i];
- }
-
- if (this.moveNum(numArr)) {
- moved = true;
-
- for (let j = 0; j < 4; j++) {
-
- this.gridMap[3 - j][i] = numArr[j];
- }
- }
- }
-
- if (moved) {
-
- const indexArr = [];
-
- for (let i = 0; i < 4; i++) {
-
- if (this.gridMap[0][i] == 0) {
-
- indexArr.push(i)
- }
- }
-
- const index = this.newIndex(indexArr);
- if (index >= 0) {
- this.gridMap[0][index] = this.newNum();
- }
- }
-
- this.gameOver = this.checkGameover();
- }
-
- moveLeft(): void {
-
- let moved = false;
-
- for (let i = 0; i < 4; i++) {
-
- const numArr = Array(4);
-
- for (let j = 0; j < 4; j++) {
-
- numArr[j] = this.gridMap[i][j];
- }
-
- if (this.moveNum(numArr)) {
- moved = true;
-
- for (let j = 0; j < 4; j++) {
-
- this.gridMap[i][j] = numArr[j];
- }
- }
- }
-
- if (moved) {
-
- const indexArr = [];
-
- for (let i = 0; i < 4; i++) {
-
- if (this.gridMap[i][3] == 0) {
-
- indexArr.push(i)
- }
- }
-
- const index = this.newIndex(indexArr);
- if (index >= 0) {
- this.gridMap[index][3] = this.newNum();
- }
- }
-
- this.gameOver = this.checkGameover();
- }
-
- moveRight(): void {
-
- let moved = false;
-
- for (let i = 0; i < 4; i++) {
-
- const numArr = Array(4);
-
- for (let j = 0; j < 4; j++) {
-
- numArr[j] = this.gridMap[i][3 - j];
- }
-
- if (this.moveNum(numArr)) {
- moved = true;
-
- for (let j = 0; j < 4; j++) {
-
- this.gridMap[i][3 - j] = numArr[j];
- }
- }
- }
-
- if (moved) {
-
- const indexArr = [];
-
- for (let i = 0; i < 4; i++) {
-
- if (this.gridMap[i][0] == 0) {
-
- indexArr.push(i)
- }
- }
-
- const index = this.newIndex(indexArr);
- if (index >= 0) {
- this.gridMap[index][0] = this.newNum();
- }
- }
-
- this.gameOver = this.checkGameover();
- }
-
- private moveNum(numArr: number[]): boolean {
-
- let moved = false;
-
- for (let i = 1; i < numArr.length; i++) {
- const num = numArr[i];
-
- if (num == 0) {
- continue;
- }
-
- for (let j = i = 1; j >= 0; j--) {
- if (numArr[j] == 0) {
-
- numArr[j] = num;
- numArr[j + 1] = 0;
- moved = true
- } else if (numArr[j] == num) {
-
- numArr[j] += num;
- numArr[j + 1] = 0;
- this.score += num * 2;
- moved = true;
- break;
- } else {
- break;
- }
- }
- }
-
- return moved
- }
-
- private newIndex(indexArr: number[]): number {
- return indexArr.length > 0 ? indexArr[Math.floor(Math.random() * indexArr.length)] : -1
- }
-
- private newNum(): number {
-
- return Math.random() > 0.3 ? 4 : 2
- }
-
- private checkGameover(): boolean {
-
- for (let i = 0; i < 4; i++) {
-
- for (let j = 0; j < 3; j++) {
-
- if (this.gridMap[i][j] == this.gridMap[i][j + 1] || this.gridMap[i][j] == 0 || this.gridMap[i][j + 1] == 0
- || this.gridMap[j][i] == this.gridMap[j + 1][i] || this.gridMap[j][i] == 0 || this.gridMap[j + 1][i] == 0) {
-
- return false
- }
- }
- }
-
- return true
- }
-
- onDraw(canvas: SPainter): void {
- canvas.clearRect(0, 0, this.width, this.height)
- canvas.pen.color = SColor.Transparent;
- this.drawMap(canvas);
- this.drawNum(canvas);
-
- if (this.gameOver) {
- canvas.brush.color = SColor.Red;
- canvas.font.size = 40;
- canvas.font.textAlign = STextAlign.Center;
- if (Date.now() % 100 > 500) {
- canvas.drawText("Game Over", 200, 200);
- }
- this.update();
- return
- }
-
- this.update();
- }
-
- drawMap(painter: SPainter) {
-
- for (let row = 0; row < 4; row++) {
-
- for (let col = 0; col < 4; col++) {
- this.drawCell(painter, row, col, this.gridMap[row][col]);
- }
- }
- }
-
- drawNum(painter: SPainter): void {
-
- for (let row = 0; row < 4; row++) {
-
- for (let col = 0; col < 4; col++) {
- this.drawCellNum(painter, row, col, this.gridMap[row][col]);
- }
- }
- }
-
- drawCellNum(painter: SPainter, row: number, col: number, type: number): void {
- const x = col * 100;
- const y = row * 100;
- if (type != 0) {
- painter.font.textAlign = STextAlign.Center;
- painter.font.size = 30;
-
- painter.brush.color = new SColor(this.color[type].font);
- painter.drawText(type + '', x + 45, y + 45);
- }
- }
-
- private drawCell(painter: SPainter, row: number, col: number, type: number): void {
- const x = col * 100 + 10;
- const y = row * 100 + 10;
- painter.brush.color = new SColor(this.color[type].background);
- painter.drawRoundRect(x, y, 90, 90, 10);
- }
- }
- @Component
- export default class Gcanvas extends Vue {
-
- view: GameView | null = null
-
- mounted(): void {
- this.view = new GameView('canvas');
- document.getElementById("canvas")!!.focus();
- }
-
- reset(): void {
-
- this.view!!.init()
- document.getElementById("canvas")!!.focus()
- }
- }
- </script>
- <style scoped lang="less">
- </style>
|