Create custom event chạm tường cho quả bóng

Bài toán của mình đặt trong tình huống là một trái banh ‘hình chữ nhật’ va chạm và phản xạ từ thành bàn. Dĩ nhiên đoạn code như thế này thì vẫn chạy tốt

            update: function () {
            this.count++;

            this.rect.x += this.rect.vx;
            this.rect.y += this.rect.vy;

            var wh = this.get_wh();
            if (this.rect.x > wh.w || this.rect.x < 0) {//su kien cham tuong dung
                this.rect.vx = -this.rect.vx;
            }

            if (this.rect.y > wh.h || this.rect.y < 0) {//su kien cham tuong ngang
                this.rect.vy = -this.rect.vy;
            }

        },

Nhưng bây giờ mình muốn cài đặt một cái sự kiện: “cham_tuong”

thì cài đặt thế nào? Trong bài toán của mình.

Toàn bộ source code như sau:

<script>

class Rect {
    constructor(x,y,w,h) {
        this.name = "Rect";
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.vx = 0;
        this.vy = 0;
    }
    draw(ctx) {
        ctx.rect(this.x,this.y,this.w,this.h);
        ctx.strokeStyle = 'blue';
        ctx.stroke();
    }
}


new Vue({
    el: '#app',
    data: {
        message: 'Hello Vue.js!',
        count: 0,
        rect:null,
    },
    mounted: function () {
        var canvas = this.get_canvas();
        var wh = { w: canvas.width, h: canvas.height }
        this.draw_rec(0, 0, wh.w, wh.h, 'blue');


        this.rect = new Rect(0, 0, 20, 10);
        this.rect.vx = 1;
        this.rect.vy = 1;

        this.run();

        var el = this.$el;
        $(el).find("canvas").bind('click', this.on_click);

        //code here
        //var event = new Event('cham_tuong');
        //$(el).find("canvas").dispatchEvent(event);
        //$(el).find("canvas").bind('cham_tuong', this.on_cham_tuong);
        //end code here

    },
    methods: {
        get_canvas: function () {
            var el = this.$el;
            var canvas = $(el).find("canvas")[0];
            return canvas;
        },
        get_ctx: function () {
            var el = this.$el;
            var ctx = $(el).find("canvas")[0].getContext('2d');
            return ctx;
        },
        get_wh: function () {
            var canvas = this.get_canvas();
            var wh = { w: canvas.width, h: canvas.height }
            return wh;
        },
        on_click: function (e) {
            //alert('click')
            var x = e.offsetX;
            var y = e.offsetY;
            this.rect.x = x;
            this.rect.y = y;
        },
        on_cham_tuong: function () {
            alert('hi');
        },
        draw_rec: function (x1, y1, x2, y2, color) {
            var ctx = this.get_ctx()
            ctx.beginPath();
            ctx.rect(x1, y1, x2, y2);
            ctx.strokeStyle = color;
            ctx.stroke();
        },
        draw_rec_fill: function (x1, y1, x2, y2, color, fill) {
            var ctx = this.get_ctx()
            ctx.beginPath();
            ctx.strokeStyle = color;
            ctx.fillStyle = fill;
            ctx.fillRect(x1, y1, x2, y2);
        },

        draw: function () {
            this.message = this.count;
            var ctx = this.get_ctx()

            this.draw_rec_fill(0, 0, this.get_wh().w, this.get_wh().h, 'red', 'yellow');
            this.rect.draw(ctx);

        },
        update: function () {
            this.count++;

            this.rect.x += this.rect.vx;
            this.rect.y += this.rect.vy;

            var wh = this.get_wh();
            if (this.rect.x > wh.w || this.rect.x < 0) {//su kien cham tuong dung
                this.rect.vx = -this.rect.vx;
            }

            if (this.rect.y > wh.h || this.rect.y < 0) {//su kien cham tuong ngang
                this.rect.vy = -this.rect.vy;
            }

        },
        run: function () {
            var that = this;
            (function tick() {
                that.update();
                that.draw();
                setTimeout(function () { that.run(); }, 37);
            })();
        }
    }


})

Minh họa giao dien thế này

Ngưỡng mộ quá, mình tập tành làm mấy cái đơn giản đã thấy khoai rồi :slight_smile:

Để anh chị dễ support em copy luôn cái phần html

<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
            <div>{{ message }}</div>
            <canvas width="200" height="100"></canvas>
</div>

Mình không biết nhiều về javascript nhưng bạn thử nghĩ đến sét điệu kiện chạm tường thì tọa độ của đường viền hình vuông nhỏ trùng tọa độ đường viền của cái bàn. Về phản xạ thì góc phản xạ bằng góc tới. Thử theo hướng đó thử xem. :slight_smile:

https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events

document thì có rất nhiều nhưng mình không biết cài đặt thế nào!!!

Nếu hàm update của bạn được gọi liên tục theo thời gian thì xem qua thử hướng dùng Swept AABB, trên gamedev có 1 bài, nó dùng để xác định 2 vật thể di chuyển có vận tốc có va chạm nhau không theo hướng tổng quát.

var event = new Event('cham_tuong');
//còn một cái gọi là dispatchEvent(event) ở khúc này không biết viết thế nào????
this.rect.addEventListener('cham_tuong',function(event){
})

optimize như thế này cũng ok như xem có vẽ ngớ ngẫn

        update: function () {
            this.count++;

            this.rect.x += this.rect.vx;
            this.rect.y += this.rect.vy;

            var wh = this.get_wh();
            if (this.rect.x > wh.w || this.rect.x < 0) {//su kien cham tuong dung

                $(document).trigger("cham_tuong_dung", { vx: this.rect.vx, vy: this.rect.vy });
                //khi nào chạm tường đứng thì phát ra một event cham_tuong_dung với thông tin vx,vy
                //this.rect.vx = -this.rect.vx;

            }

            if (this.rect.y > wh.h || this.rect.y < 0) {//su kien cham tuong ngang
                $(document).trigger("cham_tuong_ngang", { vx: this.rect.vx, vy: this.rect.vy });
                //this.rect.vy = -this.rect.vy;
            }

        },




        mounted: function () {
        var canvas = this.get_canvas();
        var wh = { w: canvas.width, h: canvas.height }
        this.draw_rec(0, 0, wh.w, wh.h, 'blue');


        this.rect = new Rect(0, 0, 20, 10);
        this.rect.vx = 1;
        this.rect.vy = 1;

        this.run();

        var el = this.$el;
        $(el).find("canvas").bind('click', this.on_click);


        var that = this;
        $(document).on("cham_tuong_dung", function (event, data) {
            //console.log(data);//Object { vx: -1, vy: -1 }
            //hehe this.rect đã chạm tường đứng với vx:-1,vy:-1
            that.rect.vx=-data.vx
        });
        $(document).on("cham_tuong_ngang", function (event, data) {
            //console.log(data);//Object { vx: -1, vy: -1 }
            //hehe this.rect đã chạm tường đứng với vx:-1,vy:-1
            that.rect.vy = -data.vy
        });

    },

uh sao lại trigger vào document, mình muốn trigger vào đối tượng Rect, làm sao đây?

đoạn code thế này lại tiếp tục ok

        mounted: function () {
        var canvas = this.get_canvas();
        var wh = { w: canvas.width, h: canvas.height }
        this.draw_rec(0, 0, wh.w, wh.h, 'blue');


        this.rect = new Rect(0, 0, 20, 10);
        this.rect.vx = 1;
        this.rect.vy = 1;

        this.run();

        var el = this.$el;
        $(el).find("canvas").bind('click', this.on_click);


        var that = this;
        //$(document).on("cham_tuong_dung", function (event, data) {
        //    //console.log(data);//Object { vx: -1, vy: -1 }
        //    //hehe this.rect đã chạm tường đứng với vx:-1,vy:-1
        //    that.rect.vx=-data.vx
        //});
        //$(document).on("cham_tuong_ngang", function (event, data) {
        //    //console.log(data);//Object { vx: -1, vy: -1 }
        //    //hehe this.rect đã chạm tường đứng với vx:-1,vy:-1
        //    that.rect.vy = -data.vy
        //});

        $(this.rect).on("cham_tuong_dung2", function (e, data) {
            //console.log(data)
            that.rect.vx = -data.vx
        })
        $(this.rect).on("cham_tuong_ngang2", function (event, data) {
            //console.log(data);//Object { vx: -1, vy: -1 }
            //hehe this.rect đã chạm tường đứng với vx:-1,vy:-1
            that.rect.vy = -data.vy
        });


    },





            update: function () {
            this.count++;

            this.rect.x += this.rect.vx;
            this.rect.y += this.rect.vy;

            var wh = this.get_wh();
            if (this.rect.x > wh.w || this.rect.x < 0) {//su kien cham tuong dung

                //$(document).trigger("cham_tuong_dung", { vx: this.rect.vx, vy: this.rect.vy });
                //khi nào chạm tường đứng thì phát ra một event cham_tuong_dung với thông tin vx,vy
                //this.rect.vx = -this.rect.vx;
                $(this.rect).trigger("cham_tuong_dung2", { vx: this.rect.vx, vy: this.rect.vy})

            }

            if (this.rect.y > wh.h || this.rect.y < 0) {//su kien cham tuong ngang
                //$(document).trigger("cham_tuong_ngang", { vx: this.rect.vx, vy: this.rect.vy });
                //this.rect.vy = -this.rect.vy;
                $(this.rect).trigger("cham_tuong_ngang2", { vx: this.rect.vx, vy: this.rect.vy })
            }

        },

hum, làm sao đẩy cái đống hầm bà lần này vào trong class của nó luôn…??? Bí rồi, help

hum, cuối cùng cũng đẩy được nó vào lớp khởi tạo. Nhờ một lá bùa copy từ mạng…

    var events = new function () {
    var _triggers = {};

    this.on = function (event, callback) {
        if (!_triggers[event])
            _triggers[event] = [];
        _triggers[event].push(callback);
    }

    this.triggerHandler = function (event, params) {
        if (_triggers[event]) {
            for (i in _triggers[event])
                _triggers[event][i](params);
        }
    }
};

full source sẽ là thế này.

<script>


var events = new function () {
    var _triggers = {};

    this.on = function (event, callback) {
        if (!_triggers[event])
            _triggers[event] = [];
        _triggers[event].push(callback);
    }

    this.triggerHandler = function (event, params) {
        if (_triggers[event]) {
            for (i in _triggers[event])
                _triggers[event][i](params);
        }
    }
};



class Rect {
    constructor(x,y,w,h) {
        this.name = "Rect";
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.vx = 0;
        this.vy = 0;
    }
    draw(ctx) {
        ctx.rect(this.x,this.y,this.w,this.h);
        ctx.strokeStyle = 'blue';
        ctx.stroke();
    }
    Cham_tuong_dung3(ww,hh) {
        if (this.x > ww || this.x < 0) {//su kien cham tuong dung
            events.triggerHandler('cham_tuong_dung3', [this.vx,this.vy]);
        }
    }
    Cham_tuong_ngang3(ww, hh) {
        if (this.y > hh || this.y < 0) {//su kien cham tuong dung
            events.triggerHandler('cham_tuong_ngang3', [this.vx, this.vy]);
        }
    }
}


new Vue({
    el: '#app',
    data: {
        message: 'Hello Vue.js!',
        count: 0,
        rect:null,
    },
    mounted: function () {
        var canvas = this.get_canvas();
        var wh = { w: canvas.width, h: canvas.height }
        this.draw_rec(0, 0, wh.w, wh.h, 'blue');

        this.rect = new Rect(0, 0, 20, 10);
        this.rect.vx = 1;
        this.rect.vy = 1;

        this.run();

        var el = this.$el;
        $(el).find("canvas").bind('click', this.on_click);

        var that = this;

        events.on('cham_tuong_dung3', function (data) {
            that.rect.vx = -data[0]
        });
        events.on('cham_tuong_ngang3', function (data) {
            that.rect.vy = -data[1]
        });

    },
    methods: {
        get_canvas: function () {
            var el = this.$el;
            var canvas = $(el).find("canvas")[0];
            return canvas;
        },
        get_ctx: function () {
            var el = this.$el;
            var ctx = $(el).find("canvas")[0].getContext('2d');
            return ctx;
        },
        get_wh: function () {
            var canvas = this.get_canvas();
            var wh = { w: canvas.width, h: canvas.height }
            return wh;
        },
        on_click: function (e) {
            //alert('click')
            var x = e.offsetX;
            var y = e.offsetY;
            this.rect.x = x;
            this.rect.y = y;
        },
        on_cham_tuong: function () {
            alert('hi');
        },
        draw_rec: function (x1, y1, x2, y2, color) {
            var ctx = this.get_ctx()
            ctx.beginPath();
            ctx.rect(x1, y1, x2, y2);
            ctx.strokeStyle = color;
            ctx.stroke();
        },
        draw_rec_fill: function (x1, y1, x2, y2, color, fill) {
            var ctx = this.get_ctx()
            ctx.beginPath();
            ctx.strokeStyle = color;
            ctx.fillStyle = fill;
            ctx.fillRect(x1, y1, x2, y2);
        },

        draw: function () {
            this.message = this.count;
            var ctx = this.get_ctx()

            this.draw_rec_fill(0, 0, this.get_wh().w, this.get_wh().h, 'red', 'yellow');
            this.rect.draw(ctx);

        },
        update: function () {
            this.count++;

            this.rect.x += this.rect.vx;
            this.rect.y += this.rect.vy;

            var wh = this.get_wh();
            this.rect.Cham_tuong_dung3(wh.w, wh.h);
            this.rect.Cham_tuong_ngang3(wh.w, wh.h);

        },
        run: function () {
            var that = this;
            (function tick() {
                that.update();
                that.draw();
                setTimeout(function () { that.run(); }, 37);
            })();
        }
    }

})

Cuối cùng là trên plunker

https://plnkr.co/edit/BYLDrl?p=preview

wait for góp ý gần xa…

Chúc mừng bạn :slight_smile:

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?