HTML5 Canvas Crazy Snake

Open in new window
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
window.requestAnimFrame = (function(callback){
    return window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function(callback){
        window.setTimeout(callback, 1000 / 60);
    };
})();
 
function getRandTheta(){
    return Math.random() * 2 * Math.PI;
}
 
function updateSnake(canvas, snake){
    var maxVariance = 0.2;
    var snakeSpeed = 200; //px / s
    var segmentsPerSecond = snakeSpeed / snake.segmentLength;
    var segments = snake.segments;
    var date = new Date();
    var time = date.getTime();
    var timeDiff = (time - snake.lastUpdateTime);
    if (timeDiff > 1000 / segmentsPerSecond) {
        var head = segments[segments.length - 1];
        var neck = segments[segments.length - 2];
 
        var direction = snake.direction;
        var newHeadX = head.x + direction.x * snake.segmentLength;
        var newHeadY = head.y + direction.y * snake.segmentLength;
 
        // change direction if collision occurs
        if (newHeadX > canvas.width || newHeadX < 0) {
            direction.x *= -1;
        }
        if (newHeadY > canvas.height || newHeadY < 0) {
            direction.y *= -1;
        }
 
        // add new segment
        segments.push({
            x: newHeadX,
            y: newHeadY
        });
 
        if (segments.length > snake.numSegments) {
            segments.shift();
        }
 
        var variance = ((maxVariance / 2) - Math.random() * maxVariance);
 
        direction.x += variance;
        direction.y -= variance;
 
        // update direction vector
        if (direction.x > 1) {
            direction.x = 1;
        }
        if (direction.x < -1) {
            direction.x = -1;
        }
 
        // dampering - try to keep direction vectors around -0.5 and +0.5
        direction.x *= Math.abs(direction.x) > 0.5 ? (1 - 0.01) : (1 + 0.01);
        direction.y *= Math.abs(direction.y) > 0.5 ? (1 - 0.01) : (1 + 0.01);
 
        snake.lastUpdateTime = time;
    }
}
 
function animate(canvas, snake){
    var context = canvas.getContext("2d");
 
    // update
    updateSnake(canvas, snake);
 
    // clear
    context.clearRect(0, 0, canvas.width, canvas.height);
 
    // draw
    drawSnake(context, snake);
 
    // request new frame
    requestAnimFrame(function(){
        animate(canvas, snake);
    });
}
 
function drawSnake(context, snake){
    var segments = snake.segments;
    var tail = segments[0];
    context.beginPath();
    context.moveTo(tail.x, tail.y);
 
    for (var n = 1; n < segments.length; n++) {
        var segment = segments[n];
        context.lineTo(segment.x, segment.y);
    }
 
    context.lineWidth = 10;
    context.lineCap = "round";
    context.lineJoin = "round";
    context.strokeStyle = "green";
    context.stroke();
}
 
window.onload = function(){
    var canvas = document.getElementById("myCanvas");
    var segmentLength = 2; // px
    var headX = canvas.width / 2;
    var headY = canvas.height / 2;
 
    snake = {
        segmentLength: 2,
        lastUpdateTime: 0,
        numSegments: 50,
        // moving to the right
        direction: {
            x: 1,
            y: 0
        },
        segments: [{
            // tail
            x: headX + segmentLength,
            y: headY
        }, {
            // head
            x: headX,
            y: headY
        }]
    };
 
    animate(canvas, snake);
};
Modified on November 21st, 2011 by Eric Rowell
comments powered by Disqus