Trò chơi ghép hình HTML

Trẻ em thích ghép các câu đố. Các trò chơi ghép hình của chúng tôi rất đơn giản nhưng vẫn cung cấp đủ thử thách để giúp trẻ xây dựng các kỹ năng như lý luận bằng hình ảnh, nhận thức không gian, trí nhớ ngắn hạn và logic. Câu đố miễn phí của chúng tôi sử dụng màu sắc tươi sáng và chủ đề vui nhộn sẽ giúp thu hút trẻ em. Mỗi câu đố cũng thay đổi một chút về độ khó để phù hợp với những người học ở các độ tuổi khác nhau

Thư giãn sau một ngày căng thẳng và thưởng thức trò chơi ghép hình tuyệt đẹp này. Hơn 300 hình ảnh tuyệt vời mang đến cho bạn nhiều chủ đề và tâm trạng khác nhau. Bất kể bạn thích thiên nhiên, động vật, nghệ thuật hay đồ ăn - chỉ cần chọn bức ảnh bạn thích nhất và bắt đầu khám phá. Tùy chỉnh câu đố của bạn bằng cách chọn số lượng mảnh ghép, bật chế độ xoay hoặc tắt chế độ xem trước nếu bạn thích thử thách hơn. Giờ vui vẻ thư giãn được đảm bảo

Đặt liên kết trò chơi trên trang web của bạn

https. //chơi. gia đình. com/jigsaw-puzzle-deluxe

Trở thành đối tác của Famobi

Bạn có một lượng truy cập đáng kể? . com

Thêm thông tin

Cho các công ty

Bạn có muốn mua, cấp phép hoặc đổi thương hiệu cho một trong những trò chơi của chúng tôi cho công ty của bạn không?

Lập trình Javascript ngày càng trở nên thú vị hơn kể từ khi các trình duyệt hiện đại bắt đầu triển khai các đặc tả HTML5 và CSS3. Một số người đã hy vọng bộ ba javascript/html5/css3 sẽ phát triển web miễn phí khỏi các plugin như Flash và Silverlight. Cho đến nay, chúng tôi đã nhận thấy vô số công cụ và khung phát triển Html5 xuất hiện ở đây và ở đó mọi lúc, cố gắng bắt kịp sự trưởng thành và trải nghiệm người dùng của các công cụ và khung Flash và Silverlight đã được thiết lập

Lần này tôi đặc biệt ấn tượng với tờ báo. khung js. Nó dễ sử dụng, rất rõ ràng và trực quan để làm việc, đồng thời cung cấp tập hợp các lớp học và sự kiện mạnh mẽ và linh hoạt. Điều này, ngoài tính linh hoạt của ngôn ngữ javascript, cho phép môi trường phát triển nhanh và hiệu quả

Sau một thời gian chơi với Paper. js, tôi quyết định tạo một trò chơi ghép hình bằng công cụ đó và chỉ khi đó quá trình học thực sự mới bắt đầu. Kết quả của hàng giờ thử và sai nằm trong bài viết này và tôi hy vọng sẽ giải thích được Giấy. js bằng cách giải thích quá trình phát triển trò chơi. Và nếu bạn không hứng thú với bài báo cũng như javascript, thì ít nhất bạn có thể sẽ chơi với trò chơi giải đố

yêu cầu hệ thống

Để sử dụng ứng dụng HTML5 Snooker Club được cung cấp trong bài viết này, tất cả những gì bạn phải làm là cài đặt hoặc có một trình duyệt web hiện đại. Chrome, Fire Fox, Maxthon, Opera, Safari hoặc Internet Explorer (9 trở lên)

Giấy. khung js

Giấy. js là, theo cách nói của họ

".. an open source vector graphics
khung kịch bản chạy trên HTML5
Canvas. Nó cung cấp một Biểu đồ cảnh / Tài liệu
Mô hình đối tượng rõ ràng và nhiều chức năng mạnh mẽ để
tạo và làm việc với đồ họa véc-tơ và bezier
curves, all neatly wrapped up in a well designed,
consistent and clean programming interface."

Vì vậy, những gì thực sự đằng sau mô tả đẹp đó? . js để thực hiện một tác vụ đơn giản là hiển thị một hình ảnh đơn giản ở giữa trình duyệt của bạn. Đoạn ngắn tiếp theo hiển thị toàn bộ html cần thiết cho tác vụ

Trò chơi ghép hình HTML

JavaScript




    
    
head>

    "canvas" class="canvas" resize>canvas>
    
Trò chơi ghép hình HTML

Một trò chơi đơn giản như vậy thoạt nhìn có vẻ đơn giản, nhưng có thể dễ dàng khiến bạn mất nhiều giờ làm việc nếu bạn không có kế hoạch rõ ràng và bạn không biết bắt đầu như thế nào. May mắn thay, trước đây tôi đã có kinh nghiệm tạo ra loại câu đố này, vì vậy lần này tôi đã có thể tránh được nhiều cạm bẫy mà tôi đã mắc phải khi phát triển ứng dụng cho bài viết câu đố đầu tiên của mình

Dưới đây là một loạt các giải pháp cho các vấn đề phổ biến nhất được tìm thấy trong ứng dụng trò chơi ghép hình

Tạo các ô hình ảnh

Khi bạn lần đầu tiên nhận thấy rằng bạn phải tạo tất cả các ô có hình dạng kỳ lạ này, như trong hình bên dưới, bạn có thể thấy nhiệm vụ này thật đáng sợ.

Trò chơi ghép hình HTML

Trên thực tế, bây giờ bạn nên quên những đường cong đó đi và tập trung vào các tác vụ cơ bản nhất trước tiên, chẳng hạn như chia hình ảnh nguồn thành các ô vuông nhỏ hoàn hảo. Mỗi mảnh trong câu đố sẽ có một phần riêng biệt của hình ảnh, do đó tất cả chúng được đặt cùng nhau có thể tạo thành toàn bộ hình ảnh. Vì vậy, hãy chia hình ảnh này thành hình vuông

Trò chơi ghép hình HTML

Bây giờ, hãy lấy một ô vuông cụ thể và sử dụng nó làm nền cho một mảnh ghép. Đây là mảnh tách ra khỏi toàn bộ

Trò chơi ghép hình HTML

Và đây là tác phẩm với hình nền của nó

Trò chơi ghép hình HTML

Bây giờ, bạn có thấy vấn đề không? . Có những khu vực gần đường viền của phần mà nền trống. Điều này xảy ra bởi vì chúng tôi đã không dự đoán rằng trong một trò chơi ghép hình, các mảnh lồng vào nhau "xâm chiếm" các khoảng trống mà đáng lẽ phải được giữ nguyên trong một trò chơi ghép hình hình vuông

Trò chơi ghép hình HTML

Theo hình trên, rõ ràng là mỗi phần nên có hình nền lớn hơn một chút để phần hình ảnh có thể vừa với. Chúng tôi làm điều này bằng cách mở rộng hình ảnh gạch cho từng phần

Trò chơi ghép hình HTML

Cắt câu đố

Phần cắt là một phần quan trọng trong ứng dụng của chúng tôi. Chúng ta phải lấy từng mảnh và cắt ra hình dạng tương ứng, để mỗi mảnh có vẻ đẹp và cong

Chúng tôi vẽ các hình bằng cách tạo một tập hợp các đường cong bezier. Đường cong Bezier rất gợi cảm và phù hợp với ứng dụng của chúng tôi. May mắn thay, tôi đã sử dụng các đường cong này trong bài viết WPF trước đây của mình và vì các tiền đề cơ bản giống nhau nên tôi đã sử dụng lại logic tương tự để xây dựng các đường cong

JavaScript

function getMask(tileRatio, topTab, rightTab, bottomTab, leftTab, tileWidth) {

    var curvyCoords = [
            0, 0, 35, 15, 37, 5,
            37, 5, 40, 0, 38, -5,
            38, -5, 20, -20, 50, -20,
            50, -20, 80, -20, 62, -5,
            62, -5, 60, 0, 63, 5,
            63, 5, 65, 15, 100, 0
    ];

    var mask = new Path();
    var tileCenter = view.center;

    var topLeftEdge = new Point(-4,4);

    mask.moveTo(topLeftEdge);

    //Top
    for (var i = 0; i < curvyCoords.length / 6; i++) {
        var p1 = topLeftEdge + new Point(curvyCoords[i * 6 + 0] * tileRatio,
        topTab * curvyCoords[i * 6 + 1] * tileRatio);
        var p2 = topLeftEdge + new Point(curvyCoords[i * 6 + 2] * tileRatio,
        topTab * curvyCoords[i * 6 + 3] * tileRatio);
        var p3 = topLeftEdge + new Point(curvyCoords[i * 6 + 4] * tileRatio,
        topTab * curvyCoords[i * 6 + 5] * tileRatio);

        mask.cubicCurveTo(p1, p2, p3);
    }
    //Right
    var topRightEdge = topLeftEdge + new Point(tileWidth, 0);
    for (var i = 0; i < curvyCoords.length / 6; i++) {
        var p1 = topRightEdge + new Point(-rightTab * curvyCoords[i * 6 + 1] * tileRatio,
        curvyCoords[i * 6 + 0] * tileRatio);
        var p2 = topRightEdge + new Point(-rightTab * curvyCoords[i * 6 + 3] * tileRatio,
        curvyCoords[i * 6 + 2] * tileRatio);
        var p3 = topRightEdge + new Point(-rightTab * curvyCoords[i * 6 + 5] * tileRatio,
        curvyCoords[i * 6 + 4] * tileRatio);

        mask.cubicCurveTo(p1, p2, p3);
    }
    //Bottom
    var bottomRightEdge = topRightEdge + new Point(0, tileWidth);
    for (var i = 0; i < curvyCoords.length / 6; i++) {
        var p1 = bottomRightEdge - new Point(curvyCoords[i * 6 + 0] * tileRatio,
        bottomTab * curvyCoords[i * 6 + 1] * tileRatio);
        var p2 = bottomRightEdge - new Point(curvyCoords[i * 6 + 2] * tileRatio,
        bottomTab * curvyCoords[i * 6 + 3] * tileRatio);
        var p3 = bottomRightEdge - new Point(curvyCoords[i * 6 + 4] * tileRatio,
        bottomTab * curvyCoords[i * 6 + 5] * tileRatio);

        mask.cubicCurveTo(p1, p2, p3);
    }
    //Left
    var bottomLeftEdge = bottomRightEdge - new Point(tileWidth, 0);
    for (var i = 0; i < curvyCoords.length / 6; i++) {
        var p1 = bottomLeftEdge - new Point(-leftTab * curvyCoords[i * 6 + 1] * tileRatio,
        curvyCoords[i * 6 + 0] * tileRatio);
        var p2 = bottomLeftEdge - new Point(-leftTab * curvyCoords[i * 6 + 3] * tileRatio,
        curvyCoords[i * 6 + 2] * tileRatio);
        var p3 = bottomLeftEdge - new Point(-leftTab * curvyCoords[i * 6 + 5] * tileRatio,
        curvyCoords[i * 6 + 4] * tileRatio);

        mask.cubicCurveTo(p1, p2, p3);
    }

    return mask;
}

Mỗi mảnh có 4 mặt (trên, dưới, trái, phải) và mỗi mặt có thể có một trong 3 dạng. bằng phẳng, một ngọn núi hoặc một thung lũng. Tất cả các hình thức này được xây dựng về cơ bản bởi cùng một chức năng. Sự khác biệt duy nhất là yếu tố được áp dụng để tính toán. 0 cho mặt phẳng, 1 cho núi và -1 cho thung lũng

The code below shows that each piece is a Group object (this is from Paper.js framework). A Group object is a composition of two or more items. The first item (mask) define the shape of the clipping, while the img item define the image background. In short, the tile image is cut out according to the shape of the mask of each piece.

JavaScript

var cloneImg = instance.puzzleImage.clone();
var img = getTileRaster(
    cloneImg,
    new Size(instance.tileWidth, instance.tileWidth),
    new Point(instance.tileWidth * x, instance.tileWidth * y)
);

var border = mask.clone();
border.strokeColor = '#ccc';
border.strokeWidth = 5;

var tile = new Group(mask, border, img, border);
tile.clipped = true;
tile.opacity = 1;

tile.shape = shape;
tile.imagePosition = new Point(x, y);

Tạo hình dạng ngẫu nhiên

Mỗi 4 cạnh của quân cờ được cho một số ngẫu nhiên trong khoảng giá trị (-1, 0, 1), xác định đường cong của cạnh đó

Trò chơi ghép hình HTML

Điều quan trọng cần lưu ý là bên trong vòng lặp tạo ra các hình dạng ngẫu nhiên, đối với mỗi lần lặp lại phần, chỉ có các cạnh bên phải và dưới cùng được cung cấp các giá trị. Khi xác định giá trị bên phải, chúng ta cũng phải xác định giá trị ngược lại cho bên trái của quân cờ ở bên phải của quân cờ đó. Điều tương tự cũng xảy ra đối với mặt dưới. nếu mặt dưới của quân cờ được cho giá trị là 1, thì mặt trên của quân cờ ở mặt dưới của quân cờ đó phải được cho giá trị -1. Nói tóm lại, các bên cạnh nhau phải luôn có các giá trị bổ sung

Trò chơi ghép hình HTML

JavaScript

function getRandomShapes(width, height) {
    var shapeArray = new Array();

    for (var y = 0; y < height; y++) {
        for (var x = 0; x < width; x++) {

            var topTab = undefined;
            var rightTab = undefined;
            var bottomTab = undefined;
            var leftTab = undefined;

            if (y == 0)
                topTab = 0;

            if (y == height - 1)
                bottomTab = 0;

            if (x == 0)
                leftTab = 0;

            if (x == width - 1)
                rightTab = 0;

            shapeArray.push(
                ({
                    topTab: topTab,
                    rightTab: rightTab,
                    bottomTab: bottomTab,
                    leftTab: leftTab
                })
            );
        }
    }

    for (var y = 0; y < height; y++) {
        for (var x = 0; x < width; x++) {

            var shape = shapeArray[y * width + x];

            var shapeRight = (x < width - 1) ?
                shapeArray[y * width + (x + 1)] :
                undefined;

            var shapeBottom = (y < height - 1) ?
                shapeArray[(y + 1) * width + x] :
                undefined;

            shape.rightTab = (x < width - 1) ?
                getRandomTabValue() :
                shape.rightTab;

            if (shapeRight)
                shapeRight.leftTab = - shape.rightTab;

            shape.bottomTab = (y < height - 1) ?
                getRandomTabValue() :
                shape.bottomTab;

            if (shapeBottom)
                shapeBottom.topTab = - shape.bottomTab;
        }
    }
    return shapeArray;
}

Vị trí ngẫu nhiên của các mảnh

Các mảnh ban đầu được định vị trong một khu vực trung tâm hình chữ nhật, nhưng có các điểm trống ngăn cách chúng. Chúng được sắp xếp theo một chức năng chọn ngẫu nhiên một quân cờ từ mảng các quân cờ, đặt nó vào bàn cờ, sau đó chọn một quân cờ khác từ các quân cờ còn lại và đặt nó vào khu vực hình vuông, cho đến khi không còn quân cờ nào

Trò chơi ghép hình HTML

JavaScript

for (var y = 0; y < yTileCount; y++) {
    for (var x = 0; x < xTileCount; x++) {

        var index1 = Math.floor(Math.random() * tileIndexes.length);
        var index2 = tileIndexes[index1];
        var tile = tiles[index2];
        tileIndexes.remove(index1, 1);

        var position = view.center -
                        new Point(instance.tileWidth, instance.tileWidth / 2) +
                        new Point(instance.tileWidth * (x * 2 + ((y % 2))), instance.tileWidth  * y) -
                        new Point(instance.puzzleImage.size.width, instance.puzzleImage.size.height / 2);

        var cellPosition = new Point(
            Math.round(position.x / instance.tileWidth) + 1,
            Math.round(position.y / instance.tileWidth) + 1);

        tile.position = cellPosition * instance.tileWidth;
        tile.cellPosition = cellPosition;
    }
}

Làm nổi bật các mảnh

Khi bạn di chuột qua các quân cờ, sẽ có một chỉ báo trực quan về lựa chọn. độ mờ của phần được chọn trở thành một nửa của bản gốc

Trò chơi ghép hình HTML

JavaScript

________số 8

Kéo và thả mảnh

Mỗi khi nút chuột trái di chuyển xuống một quân cờ đã chọn, nó sẽ được "lấy" khỏi bàn cờ và đưa ra phía trước (bằng cách phóng to kích thước của nó) và bạn có thể kéo nó trên khắp bàn cờ, cho đến khi bạn thả nút chuột để thả

JavaScript

this.pickTile = function() {
    if (instance.selectedTile) {
        if (!instance.selectedTile.lastScale) {
            instance.selectedTile.lastScale = instance.zoomScaleOnDrag;
            instance.selectedTile.scale(instance.selectedTile.lastScale);
        }
        else {
            if (instance.selectedTile.lastScale > 1) {
                instance.releaseTile();
                return;
            }
        }

        instance.selectedTile.cellPosition = undefined;

        instance.selectionGroup = new Group(instance.selectedTile);

        var pos = new Point(instance.selectedTile.position.x,
        instance.selectedTile.position.y);
        instance.selectedTile.position = new Point(0, 0);

        instance.selectionGroup.position = pos;
    }
}

this.releaseTile = function() {
    if (instance.selectedTile) {

        var cellPosition = new Point(
            Math.round(instance.selectionGroup.position.x / instance.tileWidth),
            Math.round(instance.selectionGroup.position.y / instance.tileWidth));

        var roundPosition = cellPosition * instance.tileWidth;

        var hasConflict = false;

        var alreadyPlacedTile = getTileAtCellPosition(cellPosition);

        hasConflict = alreadyPlacedTile;

        var topTile = getTileAtCellPosition(cellPosition + new Point(0, -1));
        var rightTile = getTileAtCellPosition(cellPosition + new Point(1, 0));
        var bottomTile = getTileAtCellPosition(cellPosition + new Point(0, 1));
        var leftTile = getTileAtCellPosition(cellPosition + new Point(-1, 0));

        if (topTile) {
            hasConflict = hasConflict || !(topTile.shape.bottomTab +
            instance.selectedTile.shape.topTab == 0);
        }

        if (bottomTile) {
            hasConflict = hasConflict || !(bottomTile.shape.topTab +
            instance.selectedTile.shape.bottomTab == 0);
        }

        if (rightTile) {
            hasConflict = hasConflict || !(rightTile.shape.leftTab +
            instance.selectedTile.shape.rightTab == 0);
        }

        if (leftTile) {
            hasConflict = hasConflict || !(leftTile.shape.rightTab +
            instance.selectedTile.shape.leftTab == 0);
        }

        if (!hasConflict) {

            if (instance.selectedTile.lastScale) {
                instance.selectedTile.scale(1 / instance.selectedTile.lastScale);
                instance.selectedTile.lastScale = undefined;
            }

            instance.selectionGroup.remove();
            var tile = instance.tiles[instance.selectedTileIndex];
            tile.position = roundPosition;
            tile.cellPosition = cellPosition;
            instance.selectionGroup.remove();
            instance.selectedTile =
            instance.selectionGroup = null;
            project.activeLayer.addChild(tile);

            var errors = checkTiles();
            if (errors == 0) {
                alert('Congratulations!!!');
            }
        }
    }
}

Vị trí mảnh thử nghiệm

Tuy nhiên, không phải tất cả các vị trí đều tốt để định vị một mảnh. Đầu tiên, chúng ta phải kiểm tra xem địa điểm có trống không

Và sau đó chúng tôi kiểm tra xem không có mảnh hàng xóm nào có các mặt xung đột. Các giá trị cho các bên lân cận phải luôn miễn phí

JavaScript

"canvas" class="canvas" resize>canvas>
0

Kiểm tra để hoàn thành câu đố

Mỗi khi bạn đặt một quân cờ lên bảng, ứng dụng sẽ kiểm tra việc hoàn thành câu đố. Điều này được thực hiện bởi

  • Lấy mảnh trên cùng bên trái và xác định "vị trí ô" của nó
  • Lặp lại các quân cờ khác và kiểm tra xem chúng có được định vị nhất quán hay không, sử dụng vị trí quân cờ trên cùng bên trái làm tham chiếu

JavaScript

"canvas" class="canvas" resize>canvas>
1

Sau khi hoàn thành câu đố, một thông báo đơn giản sẽ được hiển thị

Trò chơi ghép hình HTML

Có vẻ như chỉ là một tin nhắn ngớ ngẩn, nhưng nó đủ cho bài viết này

cân nhắc cuối cùng

Đó là nó. Như bạn có thể thấy, có rất nhiều chỗ để cải tiến trong ứng dụng. Giấy. js đã tự chứng minh được nhiệm vụ xử lý tập lệnh đồ họa phức tạp và xử lý sự kiện, đồng thời cung cấp một tập hợp các lớp và sự kiện rõ ràng và đơn giản

Nếu bạn có bất kỳ ý kiến, khiếu nại hoặc đề xuất nào, vui lòng để lại nhận xét bên dưới. Tôi muốn nghe ý kiến ​​từ bạn và tôi sẵn sàng cải thiện ứng dụng khi có ý tưởng mới

Môn lịch sử

  • 2012-05-31. Phiên bản đầu tiên

Giấy phép

Bài viết này, cùng với bất kỳ mã nguồn và tệp liên quan nào, được cấp phép theo Giấy phép Mở Dự án Mã (CPOL)