From d2438867dfece5cd698e0fbb0a21bcec7d6b51ab Mon Sep 17 00:00:00 2001 From: mian Date: Sat, 23 Jul 2022 12:06:21 +0300 Subject: [PATCH] Rope snake game --- rope_snake/index.html | 26 +++++++++++ rope_snake/intersect.js | 94 ++++++++++++++++++++++++++++++++++++++ rope_snake/segment.js | 59 ++++++++++++++++++++++++ rope_snake/sketch.js | 99 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 278 insertions(+) create mode 100644 rope_snake/index.html create mode 100644 rope_snake/intersect.js create mode 100644 rope_snake/segment.js create mode 100644 rope_snake/sketch.js diff --git a/rope_snake/index.html b/rope_snake/index.html new file mode 100644 index 0000000..e9d4bd7 --- /dev/null +++ b/rope_snake/index.html @@ -0,0 +1,26 @@ + + + + + + + p5.js example + + + + + + + + + +
+
+ + + diff --git a/rope_snake/intersect.js b/rope_snake/intersect.js new file mode 100644 index 0000000..85e5067 --- /dev/null +++ b/rope_snake/intersect.js @@ -0,0 +1,94 @@ +// Javascript program to check if two given line segments intersect + + +// Given three collinear points p, q, r, the function checks if +// point q lies on line segment 'pr' +function onSegment(p, q, r) +{ + if (q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && + q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y)) + return true; + + return false; +} + +// To find orientation of ordered triplet (p, q, r). +// The function returns following values +// 0 --> p, q and r are collinear +// 1 --> Clockwise +// 2 --> Counterclockwise +function orientation(p, q, r) +{ + + // See https://www.geeksforgeeks.org/orientation-3-ordered-points/ + // for details of below formula. + let val = (q.y - p.y) * (r.x - q.x) - + (q.x - p.x) * (r.y - q.y); + + if (val == 0) return 0; // collinear + + return (val > 0)? 1: 2; // clock or counterclock wise +} + +// The main function that returns true if line segment 'p1q1' +// and 'p2q2' intersect. +function doIntersect(p1, q1, p2, q2) +{ + + // Find the four orientations needed for general and + // special cases + let o1 = orientation(p1, q1, p2); + let o2 = orientation(p1, q1, q2); + let o3 = orientation(p2, q2, p1); + let o4 = orientation(p2, q2, q1); + + // General case + if (o1 != o2 && o3 != o4) + return true; + + // Special Cases + // p1, q1 and p2 are collinear and p2 lies on segment p1q1 + if (o1 == 0 && onSegment(p1, p2, q1)) return true; + + // p1, q1 and q2 are collinear and q2 lies on segment p1q1 + if (o2 == 0 && onSegment(p1, q2, q1)) return true; + + // p2, q2 and p1 are collinear and p1 lies on segment p2q2 + if (o3 == 0 && onSegment(p2, p1, q2)) return true; + + // p2, q2 and q1 are collinear and q1 lies on segment p2q2 + if (o4 == 0 && onSegment(p2, q1, q2)) return true; + + return false; // Doesn't fall in any of the above cases +} + + +function test_intersect(){ + // Driver code + let p1 = new Vector(1, 1); + let q1 = new Vector(10, 1); + let p2 = new Vector(1, 2); + let q2 = new Vector(10, 2); + + if(doIntersect(p1, q1, p2, q2)) + console.log("Yes
"); + else + console.log("No
"); + + p1 = new Vector(10, 1); q1 = new Vector(0, 10); + p2 = new Vector(0, 0); q2 = new Vector(10, 10); + if(doIntersect(p1, q1, p2, q2)) + console.log("Yes
"); + else + console.log("No
"); + + p1 = new Vector(-5, -5); q1 = new Vector(0, 0); + p2 = new Vector(1, 1); q2 = new Vector(10, 10);; + if(doIntersect(p1, q1, p2, q2)) + console.log("Yes
"); + else + console.log("No
"); +} + +// This code is contributed by avanitrachhadiya2155 + diff --git a/rope_snake/segment.js b/rope_snake/segment.js new file mode 100644 index 0000000..4493cb5 --- /dev/null +++ b/rope_snake/segment.js @@ -0,0 +1,59 @@ +const Vector = p5.Vector; + +function Segment(startx, starty, len, heading){ + this.start = new Vector(startx, starty); + this.len = len; + this.reference = 0; + this.heading = heading; + this.child = null; + this.parent = null; +}; + +Segment.prototype.end = function(){ + angle = this.heading + this.reference; + let x = this.len * cos(angle) + this.start.x; + let y = this.len * sin(angle) + this.start.y; + return new Vector(x,y); +}; + + +Segment.prototype.update = function(){ + if(!this.parent) return; + this.parent.heading = Vector.sub(this.start, this.parent.start).heading(); + this.parent.start.add(Vector.sub(this.start, this.parent.end())); + this.parent.update(); +}; + +Segment.prototype.setHeading = function(angle){ + this.heading = angle; + this.update(); +}; + +Segment.prototype.draw = function(){ + push(); + stroke(255); + strokeWeight(5); + line( + this.start.x, + this.start.y, + this.end().x, + this.end().y); + pop(); +}; + +Segment.prototype.expand_parent = function(stx, sty, len, heading){ + let next = new Segment(stx, sty, len, heading); + next.child = this; + this.parent = next; + return next; +}; + +Segment.prototype.eats_parents = function(){ + let start = this.start; + let end = this.end(); + for(let theSeg = this.parent.parent; theSeg != null; theSeg = theSeg.parent) + if(doIntersect(start, end, theSeg.start, theSeg.end())) + return true; + return false; +}; + diff --git a/rope_snake/sketch.js b/rope_snake/sketch.js new file mode 100644 index 0000000..19c22ff --- /dev/null +++ b/rope_snake/sketch.js @@ -0,0 +1,99 @@ +const START_SEGMENTS = 10; +const SEG_LEN = 10; +const SPEED = 4; +const WIDTH = 300; +const HEIGHT = 300; +const APPLE_SIZE = 20; +const APPLE_R = APPLE_SIZE/2; +const SPACE_BAR = 32; +let head; +let tail; +let apple; +let turn = 0; +let speedup = 0; + +const isOutside = (aVec) => ( + aVec.x > WIDTH || + aVec.x < 0 || + aVec.y > HEIGHT || + aVec.y < 0); + + +function setup() { + // put setup code here + apple = new Vector(random(APPLE_R,WIDTH-APPLE_R), + random(APPLE_R,HEIGHT-APPLE_R)); + tail = new Segment(WIDTH/2, 0, 10, HALF_PI); + head = tail + for(let i = 0; i < START_SEGMENTS; i++){ + let pos = head.end(); + head.child = new Segment(pos.x, pos.y, 10, HALF_PI); + head.child.parent = head; + head = head.child; + } + createCanvas(300,300); + frameRate(15); +} + +function draw() { + // put drawing code here + background(0); + for(let current = tail; current !== null; current= current.child){ + current.draw(); + } + fill(0, 255, 0); + noStroke(); + circle(apple.x, apple.y, APPLE_SIZE); + // update + head.heading += turn * PI/18; + head.start.add(p5.Vector.fromAngle(head.heading, SPEED*(1+speedup))); + head.update(); + head_end = head.end(); + if(Vector.sub(head_end, apple).mag() < APPLE_SIZE){ + apple = new Vector(random(APPLE_R,WIDTH-APPLE_R), + random(APPLE_R,HEIGHT-APPLE_R)); + for(let i=1; i<=3; i++){ + let end = tail.end(); + let heading = tail.heading; + tail = tail.expand_parent(end.x, end.y, SEG_LEN, heading+ PI); + } + } + // Game over + if(isOutside(head_end) || head.eats_parents()) + { + background(128); + textSize(HEIGHT/10); + textAlign(CENTER); + text("Game Over! Refresh page to restart.", + 0.1*WIDTH, 0.1*HEIGHT, + 0.8*WIDTH, 0.8*HEIGHT) + noLoop(); + }; +} + +function keyPressed(){ + switch(keyCode){ + case LEFT_ARROW: + turn = -1; + break; + case RIGHT_ARROW: + turn = +1; + break; + case SPACE_BAR: + speedup = 1; + break; + } +} + +function keyReleased(){ + switch(keyCode){ + case LEFT_ARROW: + case RIGHT_ARROW: + turn = 0; + break; + case SPACE_BAR: + speedup = 0; + break; + } +} +