zoukankan      html  css  js  c++  java
  • html5 迷宫游戏(碰撞检测)

    游戏效果图


    通过鼠标拖拽在画布上添加墙壁,通过方向键控制多边形上下左右移动,遇到墙壁则无法前进。

    需要解决的问题

    鼠标按下,鼠标拖动,鼠标释放事件的检测

    多边形的绘制

    墙壁的绘制

    多边形和墙壁的碰撞检测(实质上是圆和线段的相交判断)

    MYCode:

    <html>
        <head>
            <title>迷宫</title>
            <script>
                var canvas_width = 900;
                var canvas_height = 350;
                var ctx;
                var canvas;
                var everything = [];
                var cur_wall;
                var wall_width;
                var wall_style = "rgb(200,0,200)";
                var walls = [];
                var in_motion = false;
                var unit = 10;
                function Token(sx, sy, rad, style_string, n)
                {
                    this.sx = sx;
                    this.sy = sy;
                    this.rad = rad;
                    this.draw = draw_token;
                    this.n = n;
                    this.angle = (2 * Math.PI) / n;
                    this.move = move_token;
                    this.fill_style = style_string;
                }
                function draw_token()//绘制正n边形
                {
                    ctx.fill_style = this.fill_style;
                    ctx.beginPath();
                    var i;
                    var rad = this.rad;
                    ctx.moveTo(this.sx + rad * Math.cos(-0.5 * this.angle), this.sy + rad * Math.sin(-0.5 * this.angle));
                    for (i = 1; i < this.n; i++)
                        ctx.lineTo(this.sx + rad * Math.cos((i - 0.5) * this.angle), this.sy + rad * Math.sin((i - 0.5) * this.angle));
                    ctx.fill();
                }
                function move_token(dx, dy)
                {
                    this.sx += dx;
                    this.sy += dy;
                    var i;
                    var wall;
                    for (i = 0; i < walls.length; i++)
                    {
                        wall = walls[i];
                        if (intersect(wall.sx, wall.sy, wall.fx, wall.fy, this.sx, this.sy, this.rad))
                        {
                            this.sx -= dx;
                            this.sy -= dy;
                            break;
                        }
                    }
    
                }
                function Wall(sx, sy, fx, fy, width, styleString)
                {
                    this.sx = sx;
                    this.sy = sy;
                    this.fx = fx;
                    this.fy = fy;
                    this.width = width;
                    this.draw = draw_line;
                    this.strokeStyle = styleString;
                }
                function draw_line()
                {
                    ctx.lineWidth = this.width;
                    ctx.strokeStye = this.strokeStyle;
                    ctx.beginPath();
                    ctx.moveTo(this.sx, this.sy);
                    ctx.lineTo(this.fx, this.fy);
                    ctx.stroke();
                }
                //note
                var mypent = new Token(100, 100, 20, "rgb(0,0,250)", 5);
                everything.push(mypent);
                function init()
                {
                    canvas = document.getElementById("canvas");
                    ctx = canvas.getContext('2d');
                    //note
                    canvas.addEventListener('mousedown', start_wall, false);
                    canvas.addEventListener('mousemove', stretch_wall, false);
                    canvas.addEventListener('mouseup', finish_wall, false);
                    window.addEventListener('keydown', getkey_and_move, false);
                    draw_all();
                }
                function start_wall(ev)
                {
                    var mx;
                    var my;
                    if (ev.layerX || ev.layerx == 0)
                    {
                        mx = ev.layerX;
                        my = ev.layerY;
                    }
                    else if (ev.offsetX || ev.offsetX == 0)
                    {
                        mx = ev.offsetX;
                        my = ev.offsetY;
                    }
                    cur_wall = new Wall(mx, my, mx + 1, my + 1, wall_width, wall_style);
                    in_motion = true;
                    everything.push(cur_wall);
                    draw_all();
                }
                function stretch_wall(ev)
                {
                    if (in_motion)
                    {
                        var mx;
                        var my;
                        if (ev.layerX || ev.layerX == 0)
                        {
                            mx = ev.layerX;
                            my = ev.layerY;
                        }
                        else if (ev.offsetX || ev.offsetX == 0)
                        {
                            mx = ev.offsetX;
                            my = ev.offsetY;
                        }
                        cur_wall.fx = mx;
                        cur_wall.fy = my;
                        draw_all();
                    }
                }
                function finish_wall(ev)
                {
                    in_motion = false;
                    walls.push(cur_wall);
                }
                function draw_all()
                {
                    ctx.clearRect(0, 0, canvas_width, canvas_height);
                    var i;
                    for (i = 0; i < everything.length; i++)
                    {
                        everything[i].draw();
                    }
                }
                function getkey_and_move(event)
                {
                    var keyCode;
                    if (event == null)
                    {
                        keyCode = window.event.keyCode;
                        window.event.preventDefault();
                    }
                    else
                    {
                        keyCode = event.keyCode;
                        event.preventDefault();
                    }
                    switch (keyCode)
                    {
                        case 37://left arrow
                            mypent.move(-unit, 0);
                            break;
                        case 38://up arrow
                            mypent.move(0, -unit);
                            break;
                        case 39://right arrow
                            mypent.move(unit, 0);
                            break;
                        case 40:
                            mypent.move(0, unit);
                            break;
                        default:
                            //window.removeEventListener('keydown', getkey_and_move, false);
                    }
                    draw_all();
                }
                function intersect(sx, sy, fx, fy, cx, cy, rad)
                {
                    var dx;
                    var dy;
                    var t;
                    var rt;
                    dx = fx - sx;
                    dy = fy - sy;
                    t = 0.0 - (((sx - cx) * dx + (sy - cy) * dy) / (dx * dx + dy * dy));
                    if (t < 0.0)
                    {
                        t = 0.0;
                    }
                    else if (t > 1.0)
                        t = 1.0;
                    var dx1 = (sx + t * dx) - cx;
                    var dy1 = (sy + t * dy) - cy;
                    var rt = dx1 * dx1 + dy1 * dy1;
                    if (rt < rad * rad)
                        return true;
                    else
                        return false;
                }
            </script>
        <body onLoad="init();">
            <canvas id="canvas" width="900" height="350"></canvas>
        </body>
    </html>
    

    难点

    多边形和线段碰撞检测的方法

    函数intersect()负责检测多边形和线段是否相交

    记线段上一点p(x,y)

    线段2个端点是(sx,sy)和(fx,fy)

    dx=fx-sx

    dy=fy-sy

    x和y可以表示如下

    x=sx+t*dx

    y=sy+t*dy

    要判断线段和多边形是否相交,转化为判断线段和多边形的外接圆是否相交

    为此需要找到线段上离圆心o最近的一点p

    如果|op|<圆的半径,则可以判断线段和圆相交。

    否则不相交。

    怎么找到线段上离圆心距离最近的点呢?

    p点到o点的距离可以表示为

    distance=sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));

    代入

    x=sx+t*dx和y=sy+t*dy

    可以得到distance是一个关于t的函数

    对此函数求导

    求出函数值为0时对应的t值就可以得到距离圆心最近的点


  • 相关阅读:
    码农自白:这样成为谷歌工程师
    Vim命令合集
    应该知道的Linux技巧
    在Ubuntu上建立Arm Linux 开发环境
    Linux 下socket通信终极指南(附TCP、UDP完整代码)
    Socket通信原理和实践
    用 gdb 调试 GCC 程序
    Quartz学习记录
    shiro学习记录(三)
    shiro学习记录(二)
  • 原文地址:https://www.cnblogs.com/java20130725/p/3215818.html
Copyright © 2011-2022 走看看