02/12/2023
8
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
8
.idea/JS_Games.iml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/JS_Games.iml" filepath="$PROJECT_DIR$/.idea/JS_Games.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
19
.idea/php.xml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="MessDetectorOptionsConfiguration">
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PHPCSFixerOptionsConfiguration">
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PHPCodeSnifferOptionsConfiguration">
|
||||||
|
<option name="highlightLevel" value="WARNING" />
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PhpStanOptionsConfiguration">
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PsalmOptionsConfiguration">
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
54
flappy-bird/README.md
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Flappy Bird <img src="https://emojis.slackmojis.com/emojis/images/1481348711/1475/flappy_bird.png?1481348711" width="35" height="35" />
|
||||||
|
|
||||||
|
A 2D Flappy bird remake built using HTML, CSS & JS ,in which the player can control the movement of the flappy bird using right mouse click to avoid incoming obstacle.
|
||||||
|
|
||||||
|
|
||||||
|
![GitHub top language](https://img.shields.io/github/languages/top/amoldalwai/FlappyBird?style=plastic)
|
||||||
|
![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/amoldalwai/FlappyBird?style=plastic)
|
||||||
|
![Website](https://img.shields.io/website?style=plastic&url=https%3A%2F%2Famoldalwai.github.io%2FFlappyBird%2F)
|
||||||
|
|
||||||
|
#### Table of Contents
|
||||||
|
[Features](#Features)
|
||||||
|
[Youtube](#Youtube)\
|
||||||
|
[Installing](#Installing)
|
||||||
|
|
||||||
|
|
||||||
|
![Demonstartion Video](https://j.gifs.com/3Q84An.gif)
|
||||||
|
|
||||||
|
|
||||||
|
## Demo Link :point_right: [https://amoldalwai.github.io/FlappyBird/](https://amoldalwai.github.io/FlappyBird/)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- [x] Control Flappy Bird movement with right mouse click
|
||||||
|
- [x] Collision Detection
|
||||||
|
- [x] Score tracking
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Youtube
|
||||||
|
|
||||||
|
<a href="http://www.youtube.com/watch?feature=player_embedded&v=9rQIVyJJymk
|
||||||
|
" target="_blank"><img src="http://img.youtube.com/vi/9rQIVyJJymk/0.jpg"
|
||||||
|
alt="RoadFighter " width="240" height="180" border="10" /></a>
|
||||||
|
|
||||||
|
![YouTube Video Views](https://img.shields.io/youtube/views/9rQIVyJJymk?style=plastic)
|
||||||
|
![YouTube Video Votes](https://img.shields.io/youtube/likes/9rQIVyJJymk?style=social&withDislikes)
|
||||||
|
![YouTube Video Comments](https://img.shields.io/youtube/comments/9rQIVyJJymk?style=social)
|
||||||
|
|
||||||
|
|
||||||
|
### Installing
|
||||||
|
|
||||||
|
```
|
||||||
|
Run index.html on browser (eg. Chrome)
|
||||||
|
```
|
||||||
|
|
||||||
|
![Badge](https://img.shields.io/badge/Made%20by-Amol%20Dalwai-red?style=for-the-badge)
|
||||||
|
|
BIN
flappy-bird/back1.png
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
flappy-bird/back2.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
flappy-bird/background.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
177
flappy-bird/daybackground.html
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<style>
|
||||||
|
canvas {
|
||||||
|
border:1px solid #d3d3d3;
|
||||||
|
background-image: url("back2.png");
|
||||||
|
font-family: Impact, Charcoal, sans-serif;
|
||||||
|
align:center;
|
||||||
|
margin-top:100px;
|
||||||
|
margin-left:250px;
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body onload="startGame()">
|
||||||
|
<script>
|
||||||
|
var myGamePiece;
|
||||||
|
|
||||||
|
|
||||||
|
var myObstacles = [];
|
||||||
|
var myScore;
|
||||||
|
|
||||||
|
|
||||||
|
function startGame() {
|
||||||
|
myGamePiece = new component(60, 60, "flappybird.png", 100, 120, "image");
|
||||||
|
myGamePiece.gravity = 0.07;
|
||||||
|
myScore = new component("30px", "Impact", "white", 350, 40, "text");
|
||||||
|
myGameArea.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
var myGameArea = {
|
||||||
|
canvas : document.createElement("canvas"),
|
||||||
|
start : function() {
|
||||||
|
this.canvas.width = 800;
|
||||||
|
this.canvas.height = 400;
|
||||||
|
this.canvas.id="demo";
|
||||||
|
this.context = this.canvas.getContext("2d");
|
||||||
|
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
|
||||||
|
this.frameNo = 0;
|
||||||
|
this.interval = setInterval(updateGameArea, 20);
|
||||||
|
document.getElementById("demo").addEventListener("mousedown", mouseDown);
|
||||||
|
document.getElementById("demo").addEventListener("mouseup", mouseUp);
|
||||||
|
|
||||||
|
function mouseDown() {
|
||||||
|
accelerate(-0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseUp() {
|
||||||
|
accelerate(0.05);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clear : function() {
|
||||||
|
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
},
|
||||||
|
stop : function() {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function component(width, height, color, x, y, type) {
|
||||||
|
this.type = type;
|
||||||
|
this.type = type;
|
||||||
|
if (type == "image") {
|
||||||
|
this.image = new Image();
|
||||||
|
this.image.src = color;
|
||||||
|
}
|
||||||
|
this.score = 0;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.speedX = 0;
|
||||||
|
this.speedY = 0;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.gravity = 0;
|
||||||
|
this.gravitySpeed = 0;
|
||||||
|
this.update = function() {
|
||||||
|
ctx = myGameArea.context;
|
||||||
|
if (this.type == "text") {
|
||||||
|
ctx.font = this.width + " " + this.height;
|
||||||
|
ctx.fillStyle = color;
|
||||||
|
ctx.fillText(this.text, this.x, this.y);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (type == "image") {
|
||||||
|
ctx.drawImage(this.image,
|
||||||
|
this.x,
|
||||||
|
this.y,
|
||||||
|
this.width, this.height);}
|
||||||
|
|
||||||
|
else {
|
||||||
|
ctx.fillStyle = color;
|
||||||
|
ctx.fillRect(this.x, this.y, this.width, this.height);
|
||||||
|
//ctx.drawImage(myGamePiece,this.x,this.y,this.height,this.width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.newPos = function() {
|
||||||
|
this.gravitySpeed += this.gravity;
|
||||||
|
this.x += this.speedX;
|
||||||
|
this.y += this.speedY + this.gravitySpeed;
|
||||||
|
this.hitBottom();
|
||||||
|
}
|
||||||
|
this.hitBottom = function() {
|
||||||
|
var rockbottom = myGameArea.canvas.height - this.height;
|
||||||
|
if (this.y > rockbottom) {
|
||||||
|
this.y = rockbottom;
|
||||||
|
this.gravitySpeed = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.crashWith = function(otherobj) {
|
||||||
|
var myleft = this.x;
|
||||||
|
var myright = this.x + (this.width);
|
||||||
|
var mytop = this.y;
|
||||||
|
var mybottom = this.y + (this.height);
|
||||||
|
var otherleft = otherobj.x;
|
||||||
|
var otherright = otherobj.x + (otherobj.width);
|
||||||
|
var othertop = otherobj.y;
|
||||||
|
var otherbottom = otherobj.y + (otherobj.height);
|
||||||
|
var crash = true;
|
||||||
|
if ((mybottom-20< othertop) || (mytop+20> otherbottom) || (myright-20 < otherleft) || (myleft +20> otherright)) {
|
||||||
|
crash = false;
|
||||||
|
}
|
||||||
|
return crash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateGameArea() {
|
||||||
|
var x, height, gap, minHeight, maxHeight, minGap, maxGap;
|
||||||
|
for (i = 0; i < myObstacles.length; i += 1) {
|
||||||
|
if (myGamePiece.crashWith(myObstacles[i])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
myGameArea.clear();
|
||||||
|
myGameArea.frameNo += 1;
|
||||||
|
if (myGameArea.frameNo == 1 || everyinterval(130)) {
|
||||||
|
x = myGameArea.canvas.width;
|
||||||
|
minHeight = 20;
|
||||||
|
maxHeight = 200;
|
||||||
|
height = Math.floor(Math.random()*(maxHeight-minHeight+1)+minHeight);
|
||||||
|
minGap = 50;
|
||||||
|
maxGap = 200;
|
||||||
|
gap = Math.floor(Math.random()*(maxGap-minGap+1)+minGap);
|
||||||
|
// myObstacles.push(new component(10, height, "green", x, 0));
|
||||||
|
//myObstacles.push(new component(10, x - height - gap, "green", x, height + gap));
|
||||||
|
myObstacles.push(new component(50, height, "rotatedpipe.png", x, 0, "image"));
|
||||||
|
myObstacles.push(new component(50, x - height - gap, "pipe.png", x, height + gap,"image"));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
for (i = 0; i < myObstacles.length; i += 1) {
|
||||||
|
myObstacles[i].x += -2;
|
||||||
|
myObstacles[i].update();
|
||||||
|
}
|
||||||
|
myScore.text="SCORE: " + myGameArea.frameNo;
|
||||||
|
myScore.update();
|
||||||
|
myGamePiece.newPos();
|
||||||
|
myGamePiece.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
function everyinterval(n) {
|
||||||
|
if ((myGameArea.frameNo / n) % 1 == 0) {return true;}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function accelerate(n) {
|
||||||
|
myGamePiece.gravity = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
flappy-bird/flappybird.png
Normal file
After Width: | Height: | Size: 282 KiB |
10
flappy-bird/index.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<style>
|
||||||
|
.demo
|
||||||
|
{
|
||||||
|
margin-top:100px;
|
||||||
|
margin-left:250px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body><a href="modeselect.html">
|
||||||
|
<img src="menu.png" class="demo" onclick></a>
|
||||||
|
</body>
|
BIN
flappy-bird/menu.png
Normal file
After Width: | Height: | Size: 43 KiB |
10
flappy-bird/modeselect.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<style>
|
||||||
|
.demo
|
||||||
|
{
|
||||||
|
margin-top:100px;
|
||||||
|
margin-left:250px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body><a href="daybackground.html">
|
||||||
|
<img src="modeselect.png" class="demo" onclick></a>
|
||||||
|
</body>
|
BIN
flappy-bird/modeselect.png
Normal file
After Width: | Height: | Size: 50 KiB |
177
flappy-bird/nightbackground.html
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<style>
|
||||||
|
canvas {
|
||||||
|
border:1px solid #d3d3d3;
|
||||||
|
background-image: url("back1.png");
|
||||||
|
font-family: Impact, Charcoal, sans-serif;
|
||||||
|
align:center;
|
||||||
|
margin-top:100px;
|
||||||
|
margin-left:250px;
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body onload="startGame()">
|
||||||
|
<script>
|
||||||
|
var myGamePiece;
|
||||||
|
|
||||||
|
|
||||||
|
var myObstacles = [];
|
||||||
|
var myScore;
|
||||||
|
|
||||||
|
|
||||||
|
function startGame() {
|
||||||
|
myGamePiece = new component(60, 60, "flappybird.png", 100, 120, "image");
|
||||||
|
myGamePiece.gravity = 0.05;
|
||||||
|
myScore = new component("30px", "Impact", "white", 350, 40, "text");
|
||||||
|
myGameArea.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
var myGameArea = {
|
||||||
|
canvas : document.createElement("canvas"),
|
||||||
|
start : function() {
|
||||||
|
this.canvas.width = 800;
|
||||||
|
this.canvas.height = 400;
|
||||||
|
this.canvas.id="demo";
|
||||||
|
this.context = this.canvas.getContext("2d");
|
||||||
|
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
|
||||||
|
this.frameNo = 0;
|
||||||
|
this.interval = setInterval(updateGameArea, 20);
|
||||||
|
document.getElementById("demo").addEventListener("mousedown", mouseDown);
|
||||||
|
document.getElementById("demo").addEventListener("mouseup", mouseUp);
|
||||||
|
|
||||||
|
function mouseDown() {
|
||||||
|
accelerate(-0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseUp() {
|
||||||
|
accelerate(0.05);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clear : function() {
|
||||||
|
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
},
|
||||||
|
stop : function() {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function component(width, height, color, x, y, type) {
|
||||||
|
this.type = type;
|
||||||
|
this.type = type;
|
||||||
|
if (type == "image") {
|
||||||
|
this.image = new Image();
|
||||||
|
this.image.src = color;
|
||||||
|
}
|
||||||
|
this.score = 0;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.speedX = 0;
|
||||||
|
this.speedY = 0;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.gravity = 0;
|
||||||
|
this.gravitySpeed = 0;
|
||||||
|
this.update = function() {
|
||||||
|
ctx = myGameArea.context;
|
||||||
|
if (this.type == "text") {
|
||||||
|
ctx.font = this.width + " " + this.height;
|
||||||
|
ctx.fillStyle = color;
|
||||||
|
ctx.fillText(this.text, this.x, this.y);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (type == "image") {
|
||||||
|
ctx.drawImage(this.image,
|
||||||
|
this.x,
|
||||||
|
this.y,
|
||||||
|
this.width, this.height);}
|
||||||
|
|
||||||
|
else {
|
||||||
|
ctx.fillStyle = color;
|
||||||
|
ctx.fillRect(this.x, this.y, this.width, this.height);
|
||||||
|
//ctx.drawImage(myGamePiece,this.x,this.y,this.height,this.width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.newPos = function() {
|
||||||
|
this.gravitySpeed += this.gravity;
|
||||||
|
this.x += this.speedX;
|
||||||
|
this.y += this.speedY + this.gravitySpeed;
|
||||||
|
this.hitBottom();
|
||||||
|
}
|
||||||
|
this.hitBottom = function() {
|
||||||
|
var rockbottom = myGameArea.canvas.height - this.height;
|
||||||
|
if (this.y > rockbottom) {
|
||||||
|
this.y = rockbottom;
|
||||||
|
this.gravitySpeed = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.crashWith = function(otherobj) {
|
||||||
|
var myleft = this.x;
|
||||||
|
var myright = this.x + (this.width);
|
||||||
|
var mytop = this.y;
|
||||||
|
var mybottom = this.y + (this.height);
|
||||||
|
var otherleft = otherobj.x;
|
||||||
|
var otherright = otherobj.x + (otherobj.width);
|
||||||
|
var othertop = otherobj.y;
|
||||||
|
var otherbottom = otherobj.y + (otherobj.height);
|
||||||
|
var crash = true;
|
||||||
|
if ((mybottom-20< othertop) || (mytop+20> otherbottom) || (myright-20 < otherleft) || (myleft +20> otherright)) {
|
||||||
|
crash = false;
|
||||||
|
}
|
||||||
|
return crash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateGameArea() {
|
||||||
|
var x, height, gap, minHeight, maxHeight, minGap, maxGap;
|
||||||
|
for (i = 0; i < myObstacles.length; i += 1) {
|
||||||
|
if (myGamePiece.crashWith(myObstacles[i])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
myGameArea.clear();
|
||||||
|
myGameArea.frameNo += 1;
|
||||||
|
if (myGameArea.frameNo == 1 || everyinterval(130)) {
|
||||||
|
x = myGameArea.canvas.width;
|
||||||
|
minHeight = 20;
|
||||||
|
maxHeight = 200;
|
||||||
|
height = Math.floor(Math.random()*(maxHeight-minHeight+1)+minHeight);
|
||||||
|
minGap = 50;
|
||||||
|
maxGap = 200;
|
||||||
|
gap = Math.floor(Math.random()*(maxGap-minGap+1)+minGap);
|
||||||
|
// myObstacles.push(new component(10, height, "green", x, 0));
|
||||||
|
//myObstacles.push(new component(10, x - height - gap, "green", x, height + gap));
|
||||||
|
myObstacles.push(new component(50, height, "rotatedpipe.png", x, 0, "image"));
|
||||||
|
myObstacles.push(new component(50, x - height - gap, "pipe.png", x, height + gap,"image"));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
for (i = 0; i < myObstacles.length; i += 1) {
|
||||||
|
myObstacles[i].x += -2;
|
||||||
|
myObstacles[i].update();
|
||||||
|
}
|
||||||
|
myScore.text="SCORE: " + myGameArea.frameNo;
|
||||||
|
myScore.update();
|
||||||
|
myGamePiece.newPos();
|
||||||
|
myGamePiece.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
function everyinterval(n) {
|
||||||
|
if ((myGameArea.frameNo / n) % 1 == 0) {return true;}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function accelerate(n) {
|
||||||
|
myGamePiece.gravity = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
flappy-bird/pipe.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
flappy-bird/rotatedpipe.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
27
images/popcorn.svg
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="-8.21 0 141.542 141.542" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="popcorn_movie_cinema" data-name="popcorn movie cinema" transform="translate(-835.069 -127.481)">
|
||||||
|
<g id="Group_1920" data-name="Group 1920">
|
||||||
|
<path id="Path_4489" data-name="Path 4489" d="M959.4,173.13a14.516,14.516,0,1,1-14.747-14.281A14.515,14.515,0,0,1,959.4,173.13Z" fill="#fce4ab"/>
|
||||||
|
<path id="Path_4490" data-name="Path 4490" d="M878.922,166.5a17.867,17.867,0,1,1-18.152-17.576A17.867,17.867,0,0,1,878.922,166.5Z" fill="#fce4ab"/>
|
||||||
|
<path id="Path_4491" data-name="Path 4491" d="M940.9,145.059a17.867,17.867,0,1,1-18.154-17.576A17.869,17.869,0,0,1,940.9,145.059Z" fill="#fce4ab"/>
|
||||||
|
<path id="Path_4492" data-name="Path 4492" d="M920.546,150.414a22.558,22.558,0,1,1-22.918-22.19A22.559,22.559,0,0,1,920.546,150.414Z" fill="#facd7b"/>
|
||||||
|
<path id="Path_4493" data-name="Path 4493" d="M954.862,159.241a20.212,20.212,0,1,1-20.535-19.882A20.212,20.212,0,0,1,954.862,159.241Z" fill="#f9b968"/>
|
||||||
|
<path id="Path_4494" data-name="Path 4494" d="M928.547,168.712a15.523,15.523,0,1,1-15.77-15.269A15.523,15.523,0,0,1,928.547,168.712Z" fill="#ea8542"/>
|
||||||
|
<path id="Path_4495" data-name="Path 4495" d="M858.334,177.886a11.5,11.5,0,1,1-11.687-11.314A11.507,11.507,0,0,1,858.334,177.886Z" fill="#ea8542"/>
|
||||||
|
<path id="Path_4496" data-name="Path 4496" d="M908.135,170.381a15.522,15.522,0,1,1-15.771-15.267A15.524,15.524,0,0,1,908.135,170.381Z" fill="#fce4ab"/>
|
||||||
|
<path id="Path_4497" data-name="Path 4497" d="M887.07,173.067a14.517,14.517,0,1,1-14.75-14.28A14.515,14.515,0,0,1,887.07,173.067Z" fill="#f9b968"/>
|
||||||
|
</g>
|
||||||
|
<path id="Path_4498" data-name="Path 4498" d="M841.115,188.493l15.6,72.695,84.236-1.359L954.2,186.669Z" fill="#f39014"/>
|
||||||
|
<path id="Path_4499" data-name="Path 4499" d="M863.6,188.13l9.8,72.788,16.843-.272L886.2,187.765Z" fill="#e5eff3"/>
|
||||||
|
<path id="Path_4500" data-name="Path 4500" d="M841.115,188.493l15.6,72.695,16.69-.27-9.8-72.788Z" fill="#ed4d55"/>
|
||||||
|
<path id="Path_4501" data-name="Path 4501" d="M954.2,186.669l-22.816.367L923.935,260.1l17.017-.274Z" fill="#ed4d55"/>
|
||||||
|
<path id="Path_4502" data-name="Path 4502" d="M886.2,187.765l4.051,72.881,16.843-.272,1.7-72.974Z" fill="#ed4d55"/>
|
||||||
|
<path id="Path_4503" data-name="Path 4503" d="M908.789,187.4l-1.7,72.974,16.844-.271,7.446-73.066Z" fill="#e5eff3"/>
|
||||||
|
<path id="Path_4504" data-name="Path 4504" d="M847.933,220.261c20.267-9.988,55.611-22.533,104.131-21.8l2.133-11.788-113.082,1.824Z" fill="#c52c58" opacity="0.4"/>
|
||||||
|
<path id="Path_4505" data-name="Path 4505" d="M960.185,185.649a6.925,6.925,0,0,1-6.812,7.036l-111.238,1.794a6.925,6.925,0,0,1-7.036-6.811l-.029-1.847a6.925,6.925,0,0,1,6.811-7.036l111.238-1.793a6.925,6.925,0,0,1,7.036,6.811Z" fill="#ed4d55"/>
|
||||||
|
<path id="Path_4506" data-name="Path 4506" d="M945.535,234.511c-27.433,16.069-78.654,18.313-90.551,18.618l1.731,8.059,84.236-1.36Z" fill="#c52c58" opacity="0.4"/>
|
||||||
|
<path id="Path_4507" data-name="Path 4507" d="M945.235,260.684c.063,3.823-2.187,6.962-5.022,7.006l-82.507,1.332c-2.834.045-5.184-3.017-5.245-6.841l-.03-1.847c-.063-3.823,2.188-6.961,5.023-7.006L939.96,252c2.836-.046,5.184,3.016,5.246,6.841Z" fill="#ed4d55"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
71
index.php
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<title>Kergart Browser Games LTD</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<img src="images/popcorn.svg" alt="Popcorn Icon" class="header-icon popcorn">
|
||||||
|
<h1>Kergart Browser Games Ltd.</h1>
|
||||||
|
<h4>A premium amateur **** selection.<br>Only available on https://kergart.testgelaende.de!</h4>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<!-- Game sections with popcorn image -->
|
||||||
|
|
||||||
|
<section class="game">
|
||||||
|
<video src="videos/flappy-bird.mp4" class="game-video" controls autoplay loop></video>
|
||||||
|
<h2>Flappy Jan</h2>
|
||||||
|
<p>
|
||||||
|
Flappy-Jan, the wing-challenged avian adventurer, is the epitome of gravity-defying absurdity in the pixelated realm. With feathers that seem to have missed the memo on aerodynamics, Flappy-Jan embarks on a mission to redefine the art of flight – or rather, the lack thereof. Navigating through a world of pipes that apparently moonlight as overzealous decorators, our feathered friend flaps with a determination that suggests it's on a quest to discover the meaning of life, or perhaps just trying to avoid a feathery fiasco. The comical clumsiness of Flappy-Jan is a testament to the hilariously frustrating nature of the game, where every tap of the screen sends our feathered hero soaring into the chaotic symphony of pipe collisions. It's a bird-brained ballet that will leave you questioning not only your gaming skills but also the very fabric of avian physics. Good luck trying to keep a straight face while Flappy-Jan clumsily flutters through the whimsical mayhem!
|
||||||
|
</p>
|
||||||
|
<a href="flappy-bird">Play Now</a>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="game">
|
||||||
|
<video src="videos/need-for-speed.mp4" class="game-video" controls autoplay loop></video>
|
||||||
|
<h2>Need for Kergi</h2>
|
||||||
|
<p>
|
||||||
|
"Need for Kergi," the turbocharged extravaganza that transforms the asphalt into a runway for speed demons, takes the art of illegal street racing to a whole new level of fur and fury. Picture this: adrenaline-pumping cheetahs, raccoon gearheads, and hip-hop beats that even a hedgehog would breakdance to. In this anthropomorphic race fest, the asphalt jungle becomes the playground for turbocharged turtles and sleek sloths vying for supremacy in the world of underground racing. The streets are lined with neon lights, and instead of dodging traffic, our speed-hungry critters navigate through an obstacle course of acorns, banana peels, and the occasional mischievous squirrel. It's pedal-to-the-metal madness, where even the slow and steady are revving up their engines for a chance at glory. Buckle up for a wild ride as Need for Kergi unleashes the inner racer in every creature, proving that speed knows no species in this zany and fur-tastic racing adventure!
|
||||||
|
</p>
|
||||||
|
<a href="need-for-speed">Play Now</a>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="game">
|
||||||
|
<video src="videos/rock-paper-scissor.mp4" class="game-video" controls autoplay loop></video>
|
||||||
|
<h2>Jan, Jan, Jan</h2>
|
||||||
|
<p>
|
||||||
|
In the cosmic realm of "Jan, Jan, Jan," the janitorial universe unveils its quirky rendition of the classic Rock, Paper, Scissors game. Picture this whimsical jamboree: our steadfast custodian, Jan, takes the spotlight armed not with conventional weapons but equipped with a trusty mop, facing off against the formidable trio transformed into sweeping brooms, crumpled paper balls, and interlocking dustpans. The battle unfolds in a celestial dance, where the mighty mop triumphs over the unruly broom, the crumpled paper gracefully yields to the all-encompassing dustpan, and the interlocking dustpans deftly outmaneuver the crisscrossing bristles of the sweeping broom. Each round becomes a janitorial masterpiece, a testament to the cosmic prowess of Jan in this interstellar janitorial adventure. "Jan, Jan, Jan" becomes a celestial choreography where cleanliness meets the cosmos, and victory is defined by the mastery of janitorial tools in this cosmic rendition of the timeless game!
|
||||||
|
</p>
|
||||||
|
<a href="rock-paper-scissor">Play Now</a>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="game">
|
||||||
|
<video src="videos/space-drifter.mp4" class="game-video" controls autoplay loop></video>
|
||||||
|
<h2>Space Kergi</h2>
|
||||||
|
<p>
|
||||||
|
Space Jan, the cosmic maverick with a mop and a mission, embarks on an intergalactic cleaning spree that turns the vastness of space into a sparkling sanctuary. Armed with a space-age vacuum and a helmet that looks suspiciously like a janitor's cap, Space Jan maneuvers through asteroid fields and cosmic dust bunnies, tidying up the universe one celestial body at a time. Instead of dodging aliens, our celestial custodian faces off against rogue space debris and unruly stardust, determined to leave no corner of the cosmos untouched by cleanliness. The vacuum roars with the power of a rocket engine as Space Jan zips and zooms, turning space into a spick-and-span spectacle. It's not just a space adventure; it's an out-of-this-world cleanup mission that proves even the vacuum of space can't escape the meticulous touch of our cosmic custodian!
|
||||||
|
</p>
|
||||||
|
<a href="space-drifter">Play Now</a>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="game" style="margin-bottom:10%">
|
||||||
|
<video src="videos/tik-tak-toe.mp4" class="game-video" controls autoplay loop></video>
|
||||||
|
<h2>Tik-Tok-Jan</h2>
|
||||||
|
<p>
|
||||||
|
Tik-Tok-Jan, the trendsetting sensation of the grid, is a whirlwind of choreographed moves and catchy beats that transforms the classic game of tic-tac-toe into a dance-off extravaganza. Picture this: Xs and Os boogieing to the rhythm, with every move punctuated by a perfectly timed dab, floss, or maybe even a moonwalk. The grid becomes a virtual dance floor where each square is a stage for Tik-Tok-Jan to showcase its viral dance moves. Instead of the usual stoic Xs and Os, our charismatic characters strut their stuff with style, and victory isn't just about three in a row – it's about achieving the perfect dance combo. Get ready for a tic-tac-toe experience that's not only strategic but also a dance party where every move leaves you tapping your feet and wondering if you're witnessing the birth of the next big TikTok trend. It's toe-tapping, grid-hopping fun that proves tic-tac-toe isn't just a game; it's a dance revolution waiting to happen!
|
||||||
|
</p>
|
||||||
|
<a href="tik-tak-toe">Play Now</a>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>© 2023 Kergart Browser Games Ltd.<br>
|
||||||
|
and Hansi Enterprises GmbH and CoKG
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
12
need-for-speed/README.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Need For Speed - A car racing game (using JS and CSS)
|
||||||
|
|
||||||
|
Need for Speed using Javascript(JS) and CSS only.
|
||||||
|
Play here: https://ashimregme.github.io/need-for-speed
|
||||||
|
|
||||||
|
## Controls
|
||||||
|
|
||||||
|
```
|
||||||
|
Space -> Fires weapon
|
||||||
|
Left and Right Arrows -> Avoid Obstacle
|
||||||
|
```
|
||||||
|
![alt Sample Screenshot](https://github.com/ashimregme/need-for-speed/blob/master/sample.png?raw=true)
|
4
need-for-speed/css/reset.css
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*{
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
76
need-for-speed/css/style.css
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
.title{
|
||||||
|
|
||||||
|
width: 40%;
|
||||||
|
margin: 0 auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
margin: 0 auto;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid black;
|
||||||
|
height: 500px;
|
||||||
|
width: 302px;
|
||||||
|
top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
height: 2000px;
|
||||||
|
width: 100%;
|
||||||
|
background-image: url('../images/road.png');
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: repeat-y;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lane {
|
||||||
|
float: left;
|
||||||
|
width: 33.33%;
|
||||||
|
height: 500px;
|
||||||
|
min-height: 500px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lane > .car {
|
||||||
|
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 40px;
|
||||||
|
height: 80px;
|
||||||
|
margin-left: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
position: absolute;
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
border: 2px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.obstacle{
|
||||||
|
|
||||||
|
width: 100px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bullets{
|
||||||
|
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
margin-left: 13%;
|
||||||
|
bottom: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-over{
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: 40%;
|
||||||
|
background: red;
|
||||||
|
width: 80%;
|
||||||
|
padding: 10%;
|
||||||
|
text-align: center;
|
||||||
|
color: white;
|
||||||
|
font-size: 27px;
|
||||||
|
}
|
BIN
need-for-speed/images/bullets.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
need-for-speed/images/car.png
Normal file
After Width: | Height: | Size: 67 KiB |
BIN
need-for-speed/images/obstacle.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
need-for-speed/images/road.png
Normal file
After Width: | Height: | Size: 20 KiB |
32
need-for-speed/index.html
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Need for Kergi</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/reset.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/style.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class = "title">
|
||||||
|
<h1>Need for Kergi - Most Wanted</h1>
|
||||||
|
<span style="color: red">Spacebar fires bullets</span>
|
||||||
|
<br>
|
||||||
|
<span style="color: red">Press 'start' to begin</span>
|
||||||
|
<br>
|
||||||
|
<button id="toggle">Start</button>
|
||||||
|
</div>
|
||||||
|
<div class="wrapper">
|
||||||
|
<div class="container" id="container">
|
||||||
|
<div class="lane">
|
||||||
|
</div>
|
||||||
|
<div class="lane">
|
||||||
|
</div>
|
||||||
|
<div class="lane">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript" src="js/nfs.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
401
need-for-speed/js/nfs.js
Normal file
@ -0,0 +1,401 @@
|
|||||||
|
var NFS_HEIGHT = 500;
|
||||||
|
var CAR_BOTTOM = 10;
|
||||||
|
var CAR_HEIGHT = 80 + CAR_BOTTOM;
|
||||||
|
var CAR_WIDTH = 40;
|
||||||
|
var OBSTACLE_WIDTH = 100;
|
||||||
|
var OBSTACLE_HEIGHT = 33.328;
|
||||||
|
var OBSTACLE_APPEARANCE_GAP = 1000; //1 second
|
||||||
|
var OBSTACLE_APPEARANCE_DX = 100;
|
||||||
|
var PX_DX = 3;
|
||||||
|
var PX_DX_DX = 0.05;
|
||||||
|
var GAME_TIME = 1;
|
||||||
|
var GAME_TIME_DX = 11;
|
||||||
|
var INITIAL_BULLETS_BOTTOM = CAR_HEIGHT;
|
||||||
|
|
||||||
|
function Util() {}
|
||||||
|
|
||||||
|
Util.getRandomInt = function(min, max) {
|
||||||
|
|
||||||
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
|
};
|
||||||
|
|
||||||
|
function Obstacle(lanes, laneNo) {
|
||||||
|
|
||||||
|
var _this = this;
|
||||||
|
this._init = function() {
|
||||||
|
|
||||||
|
this.element = document.createElement('img');
|
||||||
|
this.laneNo = laneNo;
|
||||||
|
this.lanes = lanes;
|
||||||
|
this.element.className = 'obstacle';
|
||||||
|
this.element.setAttribute('src', 'images/obstacle.png');
|
||||||
|
this.lanes[laneNo].appendChild(this.element);
|
||||||
|
this.dynamicMarginTop = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ObstacleManager(lanes, car) {
|
||||||
|
|
||||||
|
var _this = this;
|
||||||
|
this._init = function() {
|
||||||
|
|
||||||
|
this.lanes = lanes;
|
||||||
|
this.car = car;
|
||||||
|
this.obstacles = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
this.generateObstacles = function() {
|
||||||
|
|
||||||
|
_this.obstacleGeneratorId = setInterval(_this._generateObstacle, OBSTACLE_APPEARANCE_GAP);
|
||||||
|
};
|
||||||
|
|
||||||
|
this._generateObstacle = function() {
|
||||||
|
|
||||||
|
if (_this.obstacles.length < 3) {
|
||||||
|
|
||||||
|
var laneNo;
|
||||||
|
laneNo = Util.getRandomInt(0, _this.lanes.length - 1);
|
||||||
|
var obstacle = new Obstacle(_this.lanes, laneNo);
|
||||||
|
_this.obstacles.push(obstacle);
|
||||||
|
|
||||||
|
return obstacle;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.refreshObstacles = function() {
|
||||||
|
|
||||||
|
var updatedObstacles = [];
|
||||||
|
for (var i = 0; i < _this.obstacles.length; i++) {
|
||||||
|
|
||||||
|
_this.obstacles[i].element.style.top = _this.obstacles[i].dynamicMarginTop + 'px';
|
||||||
|
if (!(parseInt(_this.obstacles[i].element.style.top) > NFS_HEIGHT - CAR_BOTTOM)) {
|
||||||
|
|
||||||
|
_this.obstacles[i].dynamicMarginTop += PX_DX;
|
||||||
|
updatedObstacles.push(_this.obstacles[i]);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
_this.obstacles[i].element.parentElement.removeChild(_this.obstacles[i].element);
|
||||||
|
for (var j = 0; j < _this.obstacles.length; j++) {
|
||||||
|
|
||||||
|
if (_this.obstacles[j].element.parentElement === _this.obstacles[i].element.parentElement) {
|
||||||
|
|
||||||
|
_this.obstacles[j].element.style.top = _this.obstacles[j].dynamicMarginTop + OBSTACLE_HEIGHT + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_this.obstacles = updatedObstacles;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.removeObstacle = function(obstacle){
|
||||||
|
|
||||||
|
var index = this.obstacles.indexOf(obstacle);
|
||||||
|
|
||||||
|
if(index !== -1){
|
||||||
|
console.log(this.obstacles[index].parentElement);
|
||||||
|
this.obstacles[index].element.parentElement.removeChild(this.obstacles[index].element);
|
||||||
|
this.obstacles.splice(index, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getOldestObstacleInLane = function(bulletLane){
|
||||||
|
|
||||||
|
var obstacle;
|
||||||
|
for(var i = 0; i < _this.obstacles.length; i++){
|
||||||
|
|
||||||
|
if(_this.obstacles[i].laneNo == bulletLane){
|
||||||
|
|
||||||
|
if(obstacle === undefined || _this.obstacles[i].dynamicMarginTop > obstacle.dynamicMarginTop){
|
||||||
|
|
||||||
|
obstacle = _this.obstacles[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return obstacle;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.stop = function() {
|
||||||
|
|
||||||
|
if (this.obstacleGeneratorId) {
|
||||||
|
clearInterval(this.obstacleGeneratorId);
|
||||||
|
this.obstacleGeneratorId = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
function CollisionHandler(car, obstacleManager) {
|
||||||
|
|
||||||
|
var _this = this;
|
||||||
|
this._init = function() {
|
||||||
|
|
||||||
|
this.car = car;
|
||||||
|
this.obstacleManager = obstacleManager;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.checkCollisions = function() {
|
||||||
|
|
||||||
|
for (var i = 0; i < _this.obstacleManager.obstacles.length; i++)
|
||||||
|
return _this._checkCollision(_this.obstacleManager.obstacles[i]);
|
||||||
|
};
|
||||||
|
|
||||||
|
this._checkCollision = function(obstacleO) {
|
||||||
|
|
||||||
|
if ((obstacleO.dynamicMarginTop + OBSTACLE_HEIGHT > NFS_HEIGHT - CAR_HEIGHT) && (obstacleO.laneNo == _this.car.currentLane)) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.checkShot = function(){
|
||||||
|
|
||||||
|
var bulletLane;
|
||||||
|
|
||||||
|
for(var i = 0; i < _this.obstacleManager.lanes.length; i++){
|
||||||
|
|
||||||
|
if(_this.obstacleManager.lanes[i].getElementsByClassName('bullets').length > 0) {
|
||||||
|
bulletLane = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var oldestObstacleInCurrentLane = obstacleManager.getOldestObstacleInLane(bulletLane);
|
||||||
|
if(oldestObstacleInCurrentLane !== undefined && _this.car.gun.bullets !== undefined) {
|
||||||
|
if (_this.car.gun.dynamicBulletBottom + oldestObstacleInCurrentLane.dynamicMarginTop + CAR_HEIGHT + OBSTACLE_HEIGHT > NFS_HEIGHT) {
|
||||||
|
|
||||||
|
_this.car.gun.stop();
|
||||||
|
_this.car.enableGun();
|
||||||
|
_this.obstacleManager.removeObstacle(oldestObstacleInCurrentLane);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(_this.car.gun.dynamicBulletBottom + CAR_HEIGHT > NFS_HEIGHT){
|
||||||
|
|
||||||
|
_this.car.gun.stop();
|
||||||
|
_this.car.enableGun();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
function Car(currentLane, lanes) {
|
||||||
|
|
||||||
|
var _this = this;
|
||||||
|
this._init = function() {
|
||||||
|
|
||||||
|
this.currentLane = currentLane;
|
||||||
|
this.lanes = lanes;
|
||||||
|
this.element = document.createElement('img');
|
||||||
|
this.element.className = 'car';
|
||||||
|
this.element.setAttribute('src', 'images/car.png');
|
||||||
|
this.lanes[this.currentLane].appendChild(this.element);
|
||||||
|
this.gun = new Gun(this.lanes);
|
||||||
|
};
|
||||||
|
|
||||||
|
this._changeLane = function(laneNumber) {
|
||||||
|
|
||||||
|
|
||||||
|
if (_this.currentLane != laneNumber) {
|
||||||
|
|
||||||
|
_this.lanes[laneNumber].appendChild(_this.element);
|
||||||
|
}
|
||||||
|
if (_this.currentLane > laneNumber) {
|
||||||
|
|
||||||
|
_this.currentLane--;
|
||||||
|
} else if (_this.currentLane < laneNumber) {
|
||||||
|
|
||||||
|
_this.currentLane++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this._keyNavigation = function(e) {
|
||||||
|
|
||||||
|
switch (e.which) {
|
||||||
|
case 37: // left
|
||||||
|
_this._changeLane((_this.currentLane - 1) < 0 ? 0 : (_this.currentLane - 1));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 39: // right
|
||||||
|
_this._changeLane((_this.currentLane + 1) > _this.lanes.length - 1 ? _this.lanes.length - 1 : (_this.currentLane + 1));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return; // exit this handler for other keys
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
this._fireGunEvent = function(e){
|
||||||
|
|
||||||
|
switch (e.which){
|
||||||
|
|
||||||
|
case 32:
|
||||||
|
_this._disableGun();
|
||||||
|
_this.gun.fireBullets(_this.currentLane);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.enableGun = function(){
|
||||||
|
|
||||||
|
document.addEventListener('keyup', this._fireGunEvent, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
this._disableGun = function(){
|
||||||
|
|
||||||
|
document.removeEventListener('keyup', this._fireGunEvent, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
this._initEvents = function() {
|
||||||
|
|
||||||
|
document.addEventListener('keydown', this._keyNavigation, false);
|
||||||
|
this.enableGun();
|
||||||
|
};
|
||||||
|
|
||||||
|
this._removeEvents = function() {
|
||||||
|
|
||||||
|
document.removeEventListener('keydown', this._keyNavigation, false);
|
||||||
|
this._disableGun();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.stop = function() {
|
||||||
|
|
||||||
|
_this._removeEvents();
|
||||||
|
};
|
||||||
|
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
function Gun(lanes){
|
||||||
|
|
||||||
|
var _this = this;
|
||||||
|
this._init = function(){
|
||||||
|
|
||||||
|
this.lanes = lanes;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fireBullets = function(currentLane){
|
||||||
|
|
||||||
|
var bullets = document.createElement('img');
|
||||||
|
bullets.setAttribute('src', 'images/bullets.png');
|
||||||
|
bullets.className = 'bullets';
|
||||||
|
_this.lanes[currentLane].appendChild(bullets);
|
||||||
|
_this.bullets = bullets;
|
||||||
|
_this.dynamicBulletBottom = INITIAL_BULLETS_BOTTOM;
|
||||||
|
|
||||||
|
_this.bulletId = requestAnimationFrame(_this.animateFireBullets);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.animateFireBullets = function () {
|
||||||
|
|
||||||
|
_this.dynamicBulletBottom += PX_DX;
|
||||||
|
_this.bullets.style.bottom = _this.dynamicBulletBottom + 'px';
|
||||||
|
|
||||||
|
_this.bulletId = requestAnimationFrame(_this.animateFireBullets);
|
||||||
|
};
|
||||||
|
|
||||||
|
_this.stop = function () {
|
||||||
|
|
||||||
|
if(_this.bulletId){
|
||||||
|
|
||||||
|
cancelAnimationFrame(_this.bulletId);
|
||||||
|
_this.bulletId = false;
|
||||||
|
_this.bullets.parentElement.removeChild(_this.bullets);
|
||||||
|
_this.bullets = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NFS() {
|
||||||
|
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
this._init = function() {
|
||||||
|
|
||||||
|
this.lanes = document.getElementsByClassName('lane');
|
||||||
|
this.container = document.getElementById('container');
|
||||||
|
this.obstacles = [];
|
||||||
|
this.car = new Car(Util.getRandomInt(0, this.lanes.length - 1), this.lanes);
|
||||||
|
this.obstacleManager = new ObstacleManager(this.lanes, this.car);
|
||||||
|
this.collisionHander = new CollisionHandler(this.car, this.obstacleManager);
|
||||||
|
|
||||||
|
this.dynamicBackgroundPositionY = 1;
|
||||||
|
|
||||||
|
document.getElementById('toggle').addEventListener('click', function() {
|
||||||
|
|
||||||
|
if (this.innerHTML == 'Start') {
|
||||||
|
_this.obstacleManager.generateObstacles();
|
||||||
|
_this.play();
|
||||||
|
_this.car._initEvents();
|
||||||
|
_this._startTime();
|
||||||
|
this.innerHTML = 'Pause';
|
||||||
|
} else if (this.innerHTML == 'Pause') {
|
||||||
|
_this.stop();
|
||||||
|
this.innerHTML = 'Start';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
this._startTime = function(){
|
||||||
|
|
||||||
|
this.timeId = setInterval(function(){GAME_TIME++;}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
this._stopTime = function(){
|
||||||
|
|
||||||
|
if(this.timeId){
|
||||||
|
|
||||||
|
clearInterval(this.timeId);
|
||||||
|
this.timeId = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.play = function() {
|
||||||
|
|
||||||
|
_this.dynamicBackgroundPositionY += PX_DX;
|
||||||
|
_this.container.style.backgroundPositionY = _this.dynamicBackgroundPositionY + 'px';
|
||||||
|
|
||||||
|
_this.obstacleManager.refreshObstacles();
|
||||||
|
|
||||||
|
if(GAME_TIME % GAME_TIME_DX == 0) {
|
||||||
|
PX_DX += PX_DX_DX;
|
||||||
|
OBSTACLE_APPEARANCE_GAP -= OBSTACLE_APPEARANCE_DX;
|
||||||
|
}
|
||||||
|
|
||||||
|
_this.playId = window.requestAnimationFrame(_this.play);
|
||||||
|
|
||||||
|
if (_this.collisionHander.checkCollisions()) {
|
||||||
|
|
||||||
|
_this.gameOver();
|
||||||
|
}
|
||||||
|
|
||||||
|
_this.collisionHander.checkShot();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.gameOver = function(){
|
||||||
|
|
||||||
|
var gameOver = document.createElement('div');
|
||||||
|
gameOver.className = 'game-over';
|
||||||
|
gameOver.innerHTML = 'GAME OVER';
|
||||||
|
_this.container.appendChild(gameOver);
|
||||||
|
_this.stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.stop = function() {
|
||||||
|
|
||||||
|
this.obstacleManager.stop();
|
||||||
|
window.cancelAnimationFrame(_this.playId);
|
||||||
|
_this.car.stop();
|
||||||
|
_this._stopTime();
|
||||||
|
};
|
||||||
|
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
var nfs = new NFS();
|
BIN
need-for-speed/sample.png
Normal file
After Width: | Height: | Size: 108 KiB |
21
rock-paper-scissor/LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 AtharvaKulkarniIT
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
48
rock-paper-scissor/README.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# Rock, Paper, Scissors Game
|
||||||
|
|
||||||
|
This is a Rock, Paper, Scissors game built with HTML, CSS, and JavaScript. You can play this classic hand game against the computer. The game is fully responsive and can be played on both desktop and mobile devices.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Play Rock, Paper, Scissors against the computer.
|
||||||
|
- Simple and intuitive user interface.
|
||||||
|
- Responsive design for both desktop and mobile devices.
|
||||||
|
- Tracks your wins, losses, and ties.
|
||||||
|
|
||||||
|
## How to Play
|
||||||
|
|
||||||
|
1. Choose your move: Rock, Paper, or Scissors by clicking on the respective button.
|
||||||
|
2. The computer will randomly select its move.
|
||||||
|
3. The winner of the round will be displayed on the screen.
|
||||||
|
4. Keep playing and try to beat the computer!
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
To run the game locally, follow these steps:
|
||||||
|
|
||||||
|
1. Clone this repository to your local machine using Git:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/AtharvaKulkarniIT/Rock-Paper-Scissor.git
|
||||||
|
|
||||||
|
That's it! You don't need to install any additional dependencies.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Simply open the `index.html` file in your web browser. You can start playing the game immediately.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! If you want to contribute to this project, follow these steps:
|
||||||
|
|
||||||
|
1. Fork the repository.
|
||||||
|
2. Create a new branch for your feature or bug fix: `git checkout -b feature/your-feature`.
|
||||||
|
3. Make your changes and commit them: `git commit -m 'Add a new feature'`.
|
||||||
|
4. Push to the branch: `git push origin feature/your-feature`.
|
||||||
|
5. Create a pull request.
|
||||||
|
|
||||||
|
Please ensure your pull request is in line with the project's coding style and standards.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
64
rock-paper-scissor/index.html
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Jan, Jan, Jan</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.2.0/css/all.css" integrity="sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ" crossorigin="anonymous">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1>Jan, Jan, Jan</h1>
|
||||||
|
</header>
|
||||||
|
<div id="inside">
|
||||||
|
|
||||||
|
|
||||||
|
<p id="instruction">Select your ammo:</p>
|
||||||
|
|
||||||
|
<div class="choice">
|
||||||
|
|
||||||
|
<div class="select-choice" id="rock">
|
||||||
|
<img class="img-weapon" src="rock1.png" alt="rock">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="select-choice" id="paper">
|
||||||
|
<img class="img-weapon" src="paper1.png" alt="paper">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="select-choice" id="scissors">
|
||||||
|
<img class="img-weapon" src="scissor1.png" alt="scissors">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="result">
|
||||||
|
|
||||||
|
<p id="message">Who will win the first game?</p>
|
||||||
|
|
||||||
|
<div class="scores">
|
||||||
|
<p class="total-score">Your score: <span id="user-score">0</span></p>
|
||||||
|
<p class="total-score">Computer's score: <span id="computer-score">0</span></p>
|
||||||
|
<p class="total-score">Draws: <span id="draws">0</span></p>
|
||||||
|
|
||||||
|
<button id="reset-button">Reset</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>By Atharva Kulkarni</p>
|
||||||
|
<p>
|
||||||
|
<a
|
||||||
|
href="https://github.com/AtharvaKulkarniIT" target="_blank"><i class="fab fa-github-alt fa-2x" alt="Github icon"></i></a>
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript" src="script.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
rock-paper-scissor/paper1.png
Normal file
After Width: | Height: | Size: 222 KiB |
BIN
rock-paper-scissor/rock-paper-scissor(AtharvaKulkarniIT.png
Normal file
After Width: | Height: | Size: 166 KiB |
BIN
rock-paper-scissor/rock1.png
Normal file
After Width: | Height: | Size: 328 KiB |
BIN
rock-paper-scissor/scissor1.png
Normal file
After Width: | Height: | Size: 210 KiB |
126
rock-paper-scissor/script.js
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
let userScore = 0;
|
||||||
|
let computerScore = 0;
|
||||||
|
let draws = 0 ;
|
||||||
|
|
||||||
|
const drawsSpan = document.getElementById("draws");
|
||||||
|
const userScoreSpan = document.getElementById("user-score");
|
||||||
|
const computerScoreSpan = document.getElementById("computer-score");
|
||||||
|
const resultDiv = document.querySelector("#message");
|
||||||
|
const resetButton = document.getElementById("reset-button")
|
||||||
|
|
||||||
|
const rockDiv = document.getElementById("rock");
|
||||||
|
const paperDiv = document.getElementById("paper");
|
||||||
|
const scissorsDiv = document.getElementById("scissors");
|
||||||
|
|
||||||
|
|
||||||
|
const getComputerChoice = () => {
|
||||||
|
const choiceList = ["rock", "paper", "scissors"];
|
||||||
|
const randomNumber = Math.floor(Math.random()*3);
|
||||||
|
return (choiceList[randomNumber]);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const convertToUp = (word) => {
|
||||||
|
switch(word) {
|
||||||
|
case "rock":
|
||||||
|
return "Jan";
|
||||||
|
break;
|
||||||
|
case "paper":
|
||||||
|
return "Jan";
|
||||||
|
break;
|
||||||
|
case "scissors":
|
||||||
|
return "Jan";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const win = (userChoice, computerChoice) => {
|
||||||
|
userScore++;
|
||||||
|
userScoreSpan.innerHTML = userScore;
|
||||||
|
const randomWin = ["beats", "smashes", "destroys", "obliterates"];
|
||||||
|
const randomNumber = Math.floor(Math.random() * 4);
|
||||||
|
const winEmojis = ["🤠","🎉", "✨","🎊","🤩","👌"]
|
||||||
|
const randomNumberEmoji = Math.floor(Math.random() * 6);
|
||||||
|
|
||||||
|
resultDiv.innerHTML = `${convertToUp(userChoice)} ${randomWin[randomNumber]} ${convertToUp(computerChoice)}. You win! ${winEmojis[randomNumberEmoji]}`;
|
||||||
|
|
||||||
|
document.getElementById(userChoice).classList.add('win-border')
|
||||||
|
setTimeout(() => document.getElementById(userChoice).classList.remove('win-border'), 600);
|
||||||
|
};
|
||||||
|
|
||||||
|
const lose = (userChoice, computerChoice) => {
|
||||||
|
computerScore++;
|
||||||
|
computerScoreSpan.innerHTML = computerScore;
|
||||||
|
const randomWin = ["beats", "smashes", "destroys", "obliterates"];
|
||||||
|
const randomNumber = Math.floor(Math.random() * 4);
|
||||||
|
const loseEmojis = ["😩", "😥 ", "😭","😵💫","😔", "🤦🏽"]
|
||||||
|
const randomNumberEmoji = Math.floor(Math.random() * 6);
|
||||||
|
resultDiv.innerHTML = `${convertToUp(computerChoice)} ${randomWin[randomNumber]} ${convertToUp(userChoice)}. You lose! ${loseEmojis[randomNumberEmoji]}`;
|
||||||
|
|
||||||
|
document.getElementById(userChoice).classList.add('lose-border');
|
||||||
|
setTimeout(() => document.getElementById(userChoice).classList.remove('lose-border'), 600);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const tie = (userChoice, computerChoice) => {
|
||||||
|
draws++;
|
||||||
|
drawsSpan.innerHTML = draws ;
|
||||||
|
const tieEmojis = ["🤔", " 😱", "🙈", "🧐", "🙀", "🙃"];
|
||||||
|
const randomNumberEmoji = Math.floor(Math.random() * 6);
|
||||||
|
resultDiv.innerHTML = `${convertToUp(computerChoice)} matches ${convertToUp(userChoice)}. It's a tie! ${tieEmojis[randomNumberEmoji]}`;
|
||||||
|
|
||||||
|
document.getElementById(userChoice).classList.add('tie-border');
|
||||||
|
setTimeout(() => document.getElementById(userChoice).classList.remove('tie-border'), 600);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const game = (userChoice) => {
|
||||||
|
const computerChoice = getComputerChoice();
|
||||||
|
|
||||||
|
switch (userChoice + computerChoice) {
|
||||||
|
case "paperrock":
|
||||||
|
case "rockscissors":
|
||||||
|
case "scissorspaper":
|
||||||
|
win(userChoice, computerChoice);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "rockpaper":
|
||||||
|
case "scissorsrock":
|
||||||
|
case "paperscissors":
|
||||||
|
lose(userChoice, computerChoice);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "rockrock":
|
||||||
|
case "paperpaper":
|
||||||
|
case "scissorsscissors":
|
||||||
|
tie(userChoice, computerChoice);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const resetScores = () => {
|
||||||
|
computerScore = 0;
|
||||||
|
computerScoreSpan.innerHTML = computerScore
|
||||||
|
userScore = 0;
|
||||||
|
userScoreSpan.innerHTML = userScore;
|
||||||
|
draws = 0;
|
||||||
|
drawsSpan.innerHTML = draws ;
|
||||||
|
resultDiv.innerHTML = 'Who will win this match ?';
|
||||||
|
};
|
||||||
|
|
||||||
|
const main = () => {
|
||||||
|
rockDiv.addEventListener('click', () => game("rock"));
|
||||||
|
|
||||||
|
paperDiv.addEventListener('click', () => game("paper"));
|
||||||
|
|
||||||
|
scissorsDiv.addEventListener('click', () => game("scissors"));
|
||||||
|
|
||||||
|
resetButton.addEventListener('click', () => resetScores());
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
main();
|
144
rock-paper-scissor/style.css
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
@import url('https://fonts.googleapis.com/css?family=Lato:400,700,900');
|
||||||
|
|
||||||
|
html{
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: 'Lato', sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
background-image: linear-gradient(180deg , #70c6e3, #19c045);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 2vh 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inside {
|
||||||
|
margin: auto;
|
||||||
|
width: 45%;
|
||||||
|
height: 50%;
|
||||||
|
border-radius: 25px;
|
||||||
|
padding: 2vh 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 3.2rem;
|
||||||
|
margin: 1vh 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#instruction {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-weapon {
|
||||||
|
max-width: 120px;
|
||||||
|
height: auto
|
||||||
|
}
|
||||||
|
|
||||||
|
.choice {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-choice {
|
||||||
|
display: inline-block;
|
||||||
|
border: 5px solid #000000;
|
||||||
|
border-radius: 80px;
|
||||||
|
margin: 1rem;
|
||||||
|
transition: all 0.6s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rock:hover, #paper:hover, #scissors:hover {
|
||||||
|
background-color: #cf6807d0;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 5px 7px 8px #888888;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#rock {
|
||||||
|
background-color: #FFEE88;
|
||||||
|
}
|
||||||
|
|
||||||
|
#paper {
|
||||||
|
background-color: #F40076;
|
||||||
|
}
|
||||||
|
|
||||||
|
#scissors {
|
||||||
|
background-color: #75C9C8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.win-border {
|
||||||
|
border: 5px solid #3bff00;
|
||||||
|
box-shadow: 2px 2px 12px #3e3e3e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lose-border {
|
||||||
|
border: 5px solid #ff0000;
|
||||||
|
box-shadow: 2px 2px 12px #3e3e3e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tie-border {
|
||||||
|
border: 5px solid #4545a3;
|
||||||
|
box-shadow: 2px 2px 12px #3e3e3e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scores {
|
||||||
|
background-color: #2eadfe;
|
||||||
|
border-radius: 25px;
|
||||||
|
opacity:0.5;
|
||||||
|
border: 1px groove black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scores>p {
|
||||||
|
color: #FFFFFF;
|
||||||
|
font-size: 1.7rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.5rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#reset-button {
|
||||||
|
border-radius: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #000000;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.5vh 0.5vw;
|
||||||
|
text-decoration: none;
|
||||||
|
margin: .2rem;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#reset-button:active {
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
line-height: 0.3rem;
|
||||||
|
padding-top: 2vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fab {
|
||||||
|
color: #000000;
|
||||||
|
margin: 0 .5%;
|
||||||
|
}
|
21
space-drifter/LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Bence A. Tóth
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
13
space-drifter/README.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Space Drifter :rocket:
|
||||||
|
|
||||||
|
A pretty darn difficult asteroid shooter game with realistic inertia and unconventional controls.
|
||||||
|
|
||||||
|
## Play the game
|
||||||
|
|
||||||
|
You can [play the game here](https://bence-toth.github.io/space-drifter/).
|
||||||
|
|
||||||
|
Have fun!
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE). Do what you will.
|
121
space-drifter/assets/asteroid-big.svg
Normal file
After Width: | Height: | Size: 18 KiB |
122
space-drifter/assets/asteroid-medium.svg
Normal file
After Width: | Height: | Size: 18 KiB |
122
space-drifter/assets/asteroid-small.svg
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
space-drifter/assets/space-drifter-cover.jpg
Normal file
After Width: | Height: | Size: 79 KiB |
BIN
space-drifter/assets/stars.png
Normal file
After Width: | Height: | Size: 75 KiB |
53
space-drifter/assets/starship.svg
Normal file
After Width: | Height: | Size: 73 KiB |
4
space-drifter/assets/torpedo.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg height="10" width="10" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="5" cy="5" r="5" fill="#00ccff" />
|
||||||
|
<circle cx="5" cy="5" r="2.5" fill="#4ddbff" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 182 B |
964
space-drifter/game.js
Normal file
@ -0,0 +1,964 @@
|
|||||||
|
// Parameters
|
||||||
|
const rotationSpeedChange = 0.1;
|
||||||
|
const movementSpeedChange = 0.01;
|
||||||
|
const torpedoLaunchSpeed = 3;
|
||||||
|
const asteroidSpeedCoefficient = 1.5;
|
||||||
|
const updateFrequency = 1000 / 60;
|
||||||
|
const dangerousTorpedoTimeout = 1000;
|
||||||
|
const explosionDuration = 1000;
|
||||||
|
const explosionMaxRadius = 100;
|
||||||
|
const explosionMaxWidth = 20;
|
||||||
|
|
||||||
|
let score = 0;
|
||||||
|
|
||||||
|
let isGameRunning = false;
|
||||||
|
let isGamePaused = false;
|
||||||
|
let gameOver = false;
|
||||||
|
|
||||||
|
const canvas = document.getElementById("game-canvas");
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
ctx.canvas.width = 1920;
|
||||||
|
ctx.canvas.height = 1080;
|
||||||
|
|
||||||
|
const getDegToRad = (degrees) => degrees * (Math.PI / 180);
|
||||||
|
|
||||||
|
const getRadToDeg = (radians) => radians * (180 / Math.PI);
|
||||||
|
|
||||||
|
const getDistance = (
|
||||||
|
{ position: { x: x1, y: y1 } },
|
||||||
|
{ position: { x: x2, y: y2 } }
|
||||||
|
) => ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5;
|
||||||
|
|
||||||
|
const getRandomDirection = () => Math.random() * 360;
|
||||||
|
|
||||||
|
const getRandomAsteroidPosition = (starship) => {
|
||||||
|
const distanceFromStarship = ctx.canvas.height / 2;
|
||||||
|
const randomDirection = getRandomDirection();
|
||||||
|
let x =
|
||||||
|
starship.position.x +
|
||||||
|
Math.cos(getDegToRad(randomDirection)) * distanceFromStarship;
|
||||||
|
let y =
|
||||||
|
starship.position.y +
|
||||||
|
Math.sin(getDegToRad(randomDirection)) * distanceFromStarship;
|
||||||
|
if (x < 0) {
|
||||||
|
x += ctx.canvas.width;
|
||||||
|
}
|
||||||
|
if (x > ctx.canvas.width) {
|
||||||
|
x -= ctx.canvas.width;
|
||||||
|
}
|
||||||
|
if (y < 0) {
|
||||||
|
y += ctx.canvas.height;
|
||||||
|
}
|
||||||
|
if (y > ctx.canvas.height) {
|
||||||
|
y -= ctx.canvas.height;
|
||||||
|
}
|
||||||
|
return { x, y };
|
||||||
|
};
|
||||||
|
|
||||||
|
let starship;
|
||||||
|
let torpedoes;
|
||||||
|
let asteroids;
|
||||||
|
let explosions;
|
||||||
|
|
||||||
|
const starshipImage = new Image();
|
||||||
|
starshipImage.src = "./assets/starship.svg";
|
||||||
|
|
||||||
|
const torpedoImage = new Image();
|
||||||
|
torpedoImage.src = "./assets/torpedo.svg";
|
||||||
|
|
||||||
|
const asteroidBigImage = new Image();
|
||||||
|
asteroidBigImage.src = "./assets/asteroid-big.svg";
|
||||||
|
|
||||||
|
const asteroidMediumImage = new Image();
|
||||||
|
asteroidMediumImage.src = "./assets/asteroid-medium.svg";
|
||||||
|
|
||||||
|
const asteroidSmallImage = new Image();
|
||||||
|
asteroidSmallImage.src = "./assets/asteroid-small.svg";
|
||||||
|
|
||||||
|
const draw = () => {
|
||||||
|
// Clear the canvas
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
// Draw the starship
|
||||||
|
if (!starship.exploded) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(starship.position.x, starship.position.y);
|
||||||
|
ctx.rotate(-1 * getDegToRad(starship.rotation - 90));
|
||||||
|
ctx.translate(-starship.position.x, -starship.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
starshipImage,
|
||||||
|
starship.position.x - starshipImage.naturalWidth / 2,
|
||||||
|
starship.position.y - starshipImage.naturalHeight / 2,
|
||||||
|
starshipImage.naturalWidth,
|
||||||
|
starshipImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
|
||||||
|
// Left edge
|
||||||
|
if (starship.position.x <= starshipImage.naturalWidth) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(
|
||||||
|
starship.position.x + ctx.canvas.width,
|
||||||
|
starship.position.y
|
||||||
|
);
|
||||||
|
ctx.rotate(-1 * getDegToRad(starship.rotation - 90));
|
||||||
|
ctx.translate(-starship.position.x, -starship.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
starshipImage,
|
||||||
|
starship.position.x - starshipImage.naturalWidth / 2,
|
||||||
|
starship.position.y - starshipImage.naturalHeight / 2,
|
||||||
|
starshipImage.naturalWidth,
|
||||||
|
starshipImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right edge
|
||||||
|
if (starship.position.x >= ctx.canvas.width - starshipImage.naturalWidth) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(
|
||||||
|
starship.position.x - ctx.canvas.width,
|
||||||
|
starship.position.y
|
||||||
|
);
|
||||||
|
ctx.rotate(-1 * getDegToRad(starship.rotation - 90));
|
||||||
|
ctx.translate(-starship.position.x, -starship.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
starshipImage,
|
||||||
|
starship.position.x - starshipImage.naturalWidth / 2,
|
||||||
|
starship.position.y - starshipImage.naturalHeight / 2,
|
||||||
|
starshipImage.naturalWidth,
|
||||||
|
starshipImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top edge
|
||||||
|
if (starship.position.y <= starshipImage.naturalHeight) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(
|
||||||
|
starship.position.x,
|
||||||
|
starship.position.y + ctx.canvas.height
|
||||||
|
);
|
||||||
|
ctx.rotate(-1 * getDegToRad(starship.rotation - 90));
|
||||||
|
ctx.translate(-starship.position.x, -starship.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
starshipImage,
|
||||||
|
starship.position.x - starshipImage.naturalWidth / 2,
|
||||||
|
starship.position.y - starshipImage.naturalHeight / 2,
|
||||||
|
starshipImage.naturalWidth,
|
||||||
|
starshipImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom edge
|
||||||
|
if (
|
||||||
|
starship.position.y >=
|
||||||
|
ctx.canvas.height - starshipImage.naturalHeight
|
||||||
|
) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(
|
||||||
|
starship.position.x,
|
||||||
|
starship.position.y - ctx.canvas.height
|
||||||
|
);
|
||||||
|
ctx.rotate(-1 * getDegToRad(starship.rotation - 90));
|
||||||
|
ctx.translate(-starship.position.x, -starship.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
starshipImage,
|
||||||
|
starship.position.x - starshipImage.naturalWidth / 2,
|
||||||
|
starship.position.y - starshipImage.naturalHeight / 2,
|
||||||
|
starshipImage.naturalWidth,
|
||||||
|
starshipImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top left corner
|
||||||
|
if (
|
||||||
|
starship.position.x <= starshipImage.naturalWidth &&
|
||||||
|
starship.position.y <= starshipImage.naturalHeight
|
||||||
|
) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(
|
||||||
|
starship.position.x + ctx.canvas.width,
|
||||||
|
starship.position.y + ctx.canvas.height
|
||||||
|
);
|
||||||
|
ctx.rotate(-1 * getDegToRad(starship.rotation - 90));
|
||||||
|
ctx.translate(-starship.position.x, -starship.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
starshipImage,
|
||||||
|
starship.position.x - starshipImage.naturalWidth / 2,
|
||||||
|
starship.position.y - starshipImage.naturalHeight / 2,
|
||||||
|
starshipImage.naturalWidth,
|
||||||
|
starshipImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom left corner
|
||||||
|
if (
|
||||||
|
starship.position.x <= starshipImage.naturalWidth &&
|
||||||
|
starship.position.y >= ctx.canvas.height - starshipImage.naturalHeight
|
||||||
|
) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(
|
||||||
|
starship.position.x + ctx.canvas.width,
|
||||||
|
starship.position.y - ctx.canvas.height
|
||||||
|
);
|
||||||
|
ctx.rotate(-1 * getDegToRad(starship.rotation - 90));
|
||||||
|
ctx.translate(-starship.position.x, -starship.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
starshipImage,
|
||||||
|
starship.position.x - starshipImage.naturalWidth / 2,
|
||||||
|
starship.position.y - starshipImage.naturalHeight / 2,
|
||||||
|
starshipImage.naturalWidth,
|
||||||
|
starshipImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top right corner
|
||||||
|
if (
|
||||||
|
starship.position.x >= ctx.canvas.width - starshipImage.naturalWidth &&
|
||||||
|
starship.position.y <= starshipImage.naturalHeight
|
||||||
|
) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(
|
||||||
|
starship.position.x - ctx.canvas.width,
|
||||||
|
starship.position.y + ctx.canvas.height
|
||||||
|
);
|
||||||
|
ctx.rotate(-1 * getDegToRad(starship.rotation - 90));
|
||||||
|
ctx.translate(-starship.position.x, -starship.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
starshipImage,
|
||||||
|
starship.position.x - starshipImage.naturalWidth / 2,
|
||||||
|
starship.position.y - starshipImage.naturalHeight / 2,
|
||||||
|
starshipImage.naturalWidth,
|
||||||
|
starshipImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom right corner
|
||||||
|
if (
|
||||||
|
starship.position.y >= ctx.canvas.height - starshipImage.naturalHeight &&
|
||||||
|
starship.position.x >= ctx.canvas.width - starshipImage.naturalWidth
|
||||||
|
) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(
|
||||||
|
starship.position.x - ctx.canvas.width,
|
||||||
|
starship.position.y - ctx.canvas.height
|
||||||
|
);
|
||||||
|
ctx.rotate(-1 * getDegToRad(starship.rotation - 90));
|
||||||
|
ctx.translate(-starship.position.x, -starship.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
starshipImage,
|
||||||
|
starship.position.x - starshipImage.naturalWidth / 2,
|
||||||
|
starship.position.y - starshipImage.naturalHeight / 2,
|
||||||
|
starshipImage.naturalWidth,
|
||||||
|
starshipImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the torpedoes
|
||||||
|
torpedoes.forEach((torpedo) => {
|
||||||
|
ctx.drawImage(
|
||||||
|
torpedoImage,
|
||||||
|
torpedo.position.x - torpedoImage.naturalWidth / 2,
|
||||||
|
torpedo.position.y - torpedoImage.naturalHeight / 2,
|
||||||
|
torpedoImage.naturalWidth,
|
||||||
|
torpedoImage.naturalHeight
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Draw the asteroids
|
||||||
|
asteroids.forEach((asteroid) => {
|
||||||
|
let asteroidImage;
|
||||||
|
if (asteroid.size === 2) {
|
||||||
|
asteroidImage = asteroidBigImage;
|
||||||
|
}
|
||||||
|
if (asteroid.size === 1) {
|
||||||
|
asteroidImage = asteroidMediumImage;
|
||||||
|
}
|
||||||
|
if (asteroid.size === 0) {
|
||||||
|
asteroidImage = asteroidSmallImage;
|
||||||
|
}
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(asteroid.position.x, asteroid.position.y);
|
||||||
|
ctx.rotate(-1 * getDegToRad(asteroid.rotation - 90));
|
||||||
|
ctx.translate(-asteroid.position.x, -asteroid.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
asteroidImage,
|
||||||
|
asteroid.position.x - asteroidImage.naturalWidth / 2,
|
||||||
|
asteroid.position.y - asteroidImage.naturalHeight / 2,
|
||||||
|
asteroidImage.naturalWidth,
|
||||||
|
asteroidImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
|
||||||
|
// Left edge
|
||||||
|
if (asteroid.position.x <= asteroidImage.naturalWidth) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(
|
||||||
|
asteroid.position.x + ctx.canvas.width,
|
||||||
|
asteroid.position.y
|
||||||
|
);
|
||||||
|
ctx.rotate(-1 * getDegToRad(asteroid.rotation - 90));
|
||||||
|
ctx.translate(-asteroid.position.x, -asteroid.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
asteroidImage,
|
||||||
|
asteroid.position.x - asteroidImage.naturalWidth / 2,
|
||||||
|
asteroid.position.y - asteroidImage.naturalHeight / 2,
|
||||||
|
asteroidImage.naturalWidth,
|
||||||
|
asteroidImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right edge
|
||||||
|
if (asteroid.position.x >= ctx.canvas.width - asteroidImage.naturalWidth) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(
|
||||||
|
asteroid.position.x - ctx.canvas.width,
|
||||||
|
asteroid.position.y
|
||||||
|
);
|
||||||
|
ctx.rotate(-1 * getDegToRad(asteroid.rotation - 90));
|
||||||
|
ctx.translate(-asteroid.position.x, -asteroid.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
asteroidImage,
|
||||||
|
asteroid.position.x - asteroidImage.naturalWidth / 2,
|
||||||
|
asteroid.position.y - asteroidImage.naturalHeight / 2,
|
||||||
|
asteroidImage.naturalWidth,
|
||||||
|
asteroidImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top edge
|
||||||
|
if (asteroid.position.y <= asteroidImage.naturalHeight) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(
|
||||||
|
asteroid.position.x,
|
||||||
|
asteroid.position.y + ctx.canvas.height
|
||||||
|
);
|
||||||
|
ctx.rotate(-1 * getDegToRad(asteroid.rotation - 90));
|
||||||
|
ctx.translate(-asteroid.position.x, -asteroid.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
asteroidImage,
|
||||||
|
asteroid.position.x - asteroidImage.naturalWidth / 2,
|
||||||
|
asteroid.position.y - asteroidImage.naturalHeight / 2,
|
||||||
|
asteroidImage.naturalWidth,
|
||||||
|
asteroidImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom edge
|
||||||
|
if (
|
||||||
|
asteroid.position.y >=
|
||||||
|
ctx.canvas.height - asteroidImage.naturalHeight
|
||||||
|
) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(
|
||||||
|
asteroid.position.x,
|
||||||
|
asteroid.position.y - ctx.canvas.height
|
||||||
|
);
|
||||||
|
ctx.rotate(-1 * getDegToRad(asteroid.rotation - 90));
|
||||||
|
ctx.translate(-asteroid.position.x, -asteroid.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
asteroidImage,
|
||||||
|
asteroid.position.x - asteroidImage.naturalWidth / 2,
|
||||||
|
asteroid.position.y - asteroidImage.naturalHeight / 2,
|
||||||
|
asteroidImage.naturalWidth,
|
||||||
|
asteroidImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top left corner
|
||||||
|
if (
|
||||||
|
asteroid.position.x <= asteroidImage.naturalWidth &&
|
||||||
|
asteroid.position.y <= asteroidImage.naturalHeight
|
||||||
|
) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(
|
||||||
|
asteroid.position.x + ctx.canvas.width,
|
||||||
|
asteroid.position.y + ctx.canvas.height
|
||||||
|
);
|
||||||
|
ctx.rotate(-1 * getDegToRad(asteroid.rotation - 90));
|
||||||
|
ctx.translate(-asteroid.position.x, -asteroid.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
asteroidImage,
|
||||||
|
asteroid.position.x - asteroidImage.naturalWidth / 2,
|
||||||
|
asteroid.position.y - asteroidImage.naturalHeight / 2,
|
||||||
|
asteroidImage.naturalWidth,
|
||||||
|
asteroidImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom left corner
|
||||||
|
if (
|
||||||
|
asteroid.position.x <= asteroidImage.naturalWidth &&
|
||||||
|
asteroid.position.y >= ctx.canvas.height - asteroidImage.naturalHeight
|
||||||
|
) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(
|
||||||
|
asteroid.position.x + ctx.canvas.width,
|
||||||
|
asteroid.position.y - ctx.canvas.height
|
||||||
|
);
|
||||||
|
ctx.rotate(-1 * getDegToRad(asteroid.rotation - 90));
|
||||||
|
ctx.translate(-asteroid.position.x, -asteroid.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
asteroidImage,
|
||||||
|
asteroid.position.x - asteroidImage.naturalWidth / 2,
|
||||||
|
asteroid.position.y - asteroidImage.naturalHeight / 2,
|
||||||
|
asteroidImage.naturalWidth,
|
||||||
|
asteroidImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top right corner
|
||||||
|
if (
|
||||||
|
asteroid.position.x >= ctx.canvas.width - asteroidImage.naturalWidth &&
|
||||||
|
asteroid.position.y <= asteroidImage.naturalHeight
|
||||||
|
) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(
|
||||||
|
asteroid.position.x - ctx.canvas.width,
|
||||||
|
asteroid.position.y + ctx.canvas.height
|
||||||
|
);
|
||||||
|
ctx.rotate(-1 * getDegToRad(asteroid.rotation - 90));
|
||||||
|
ctx.translate(-asteroid.position.x, -asteroid.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
asteroidImage,
|
||||||
|
asteroid.position.x - asteroidImage.naturalWidth / 2,
|
||||||
|
asteroid.position.y - asteroidImage.naturalHeight / 2,
|
||||||
|
asteroidImage.naturalWidth,
|
||||||
|
asteroidImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom right corner
|
||||||
|
if (
|
||||||
|
asteroid.position.x >= ctx.canvas.width - asteroidImage.naturalWidth &&
|
||||||
|
asteroid.position.y >= ctx.canvas.height - asteroidImage.naturalHeight
|
||||||
|
) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(
|
||||||
|
asteroid.position.x - ctx.canvas.width,
|
||||||
|
asteroid.position.y - ctx.canvas.height
|
||||||
|
);
|
||||||
|
ctx.rotate(-1 * getDegToRad(asteroid.rotation - 90));
|
||||||
|
ctx.translate(-asteroid.position.x, -asteroid.position.y);
|
||||||
|
ctx.drawImage(
|
||||||
|
asteroidImage,
|
||||||
|
asteroid.position.x - asteroidImage.naturalWidth / 2,
|
||||||
|
asteroid.position.y - asteroidImage.naturalHeight / 2,
|
||||||
|
asteroidImage.naturalWidth,
|
||||||
|
asteroidImage.naturalHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Draw the explosions
|
||||||
|
const now = Date.now();
|
||||||
|
explosions.forEach((explosion) => {
|
||||||
|
const explosionProgress = (now - explosion.startedAt) / explosionDuration;
|
||||||
|
const explosionRadius =
|
||||||
|
torpedoImage.naturalWidth + explosionProgress * explosionMaxRadius;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(
|
||||||
|
explosion.position.x,
|
||||||
|
explosion.position.y,
|
||||||
|
explosionRadius,
|
||||||
|
0,
|
||||||
|
2 * Math.PI
|
||||||
|
);
|
||||||
|
ctx.strokeStyle = `hsla(0, 0%, 100%, ${Math.max(
|
||||||
|
0.75 * 1 - explosionProgress,
|
||||||
|
0
|
||||||
|
)})`;
|
||||||
|
ctx.lineWidth = 1 + explosionProgress * explosionMaxWidth;
|
||||||
|
ctx.stroke();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Request next frame
|
||||||
|
if (isGameRunning && !isGamePaused) {
|
||||||
|
requestAnimationFrame(draw);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let rotationMomentumChangeInterval = null;
|
||||||
|
let forwardSpeedChangeInterval = null;
|
||||||
|
|
||||||
|
const fireTorpedo = () => {
|
||||||
|
starship.canFire = false;
|
||||||
|
setTimeout(() => {
|
||||||
|
starship.canFire = true;
|
||||||
|
}, 500);
|
||||||
|
const moveVector = {
|
||||||
|
x:
|
||||||
|
(Math.cos(getDegToRad(starship.rotation)) || 0) *
|
||||||
|
(starship.forwardSpeed + torpedoLaunchSpeed),
|
||||||
|
y:
|
||||||
|
(Math.sin(getDegToRad(starship.rotation)) || 0) *
|
||||||
|
(starship.forwardSpeed + torpedoLaunchSpeed),
|
||||||
|
};
|
||||||
|
const driftVector = {
|
||||||
|
x:
|
||||||
|
(Math.cos(getDegToRad(starship.driftDirection)) || 0) *
|
||||||
|
starship.driftSpeed,
|
||||||
|
y:
|
||||||
|
(Math.sin(getDegToRad(starship.driftDirection)) || 0) *
|
||||||
|
starship.driftSpeed,
|
||||||
|
};
|
||||||
|
const deltaXDrift = driftVector.x + moveVector.x;
|
||||||
|
const deltaYDrift = driftVector.y + moveVector.y;
|
||||||
|
let direction;
|
||||||
|
if (starship.driftSpeed === 0) {
|
||||||
|
direction = starship.rotation;
|
||||||
|
} else {
|
||||||
|
direction =
|
||||||
|
getRadToDeg(Math.atan(deltaYDrift / deltaXDrift || 0)) +
|
||||||
|
(deltaXDrift < 0 ? 180 : 0);
|
||||||
|
}
|
||||||
|
const speed = (deltaXDrift ** 2 + deltaYDrift ** 2) ** 0.5;
|
||||||
|
torpedoes.push({
|
||||||
|
position: {
|
||||||
|
x: starship.position.x,
|
||||||
|
y: starship.position.y,
|
||||||
|
},
|
||||||
|
direction,
|
||||||
|
speed,
|
||||||
|
detonated: false,
|
||||||
|
launchedAt: Date.now(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("keydown", (event) => {
|
||||||
|
if (!isGameRunning) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.key === "p" || event.key === "P") {
|
||||||
|
if (isGamePaused) {
|
||||||
|
document.getElementById("paused").classList.add("hidden");
|
||||||
|
isGamePaused = false;
|
||||||
|
clock = setInterval(tick, updateFrequency);
|
||||||
|
requestAnimationFrame(draw);
|
||||||
|
} else {
|
||||||
|
if (gameOver) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
document.getElementById("paused").classList.remove("hidden");
|
||||||
|
isGamePaused = true;
|
||||||
|
clearInterval(clock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isGamePaused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.key === "ArrowLeft" || event.key === "a" || event.key === "A") {
|
||||||
|
starship.rotationMomentum += rotationSpeedChange;
|
||||||
|
clearInterval(rotationMomentumChangeInterval);
|
||||||
|
rotationMomentumChangeInterval = setInterval(() => {
|
||||||
|
starship.rotationMomentum += rotationSpeedChange;
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
if (event.key === "ArrowRight" || event.key === "d" || event.key === "D") {
|
||||||
|
starship.rotationMomentum -= rotationSpeedChange;
|
||||||
|
clearInterval(rotationMomentumChangeInterval);
|
||||||
|
rotationMomentumChangeInterval = setInterval(() => {
|
||||||
|
starship.rotationMomentum -= rotationSpeedChange;
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
if (event.key === "ArrowUp" || event.key === "w" || event.key === "W") {
|
||||||
|
if (starship.forwardSpeed < 0) {
|
||||||
|
starship.forwardSpeed = 0;
|
||||||
|
}
|
||||||
|
starship.forwardSpeed += movementSpeedChange;
|
||||||
|
clearInterval(forwardSpeedChangeInterval);
|
||||||
|
forwardSpeedChangeInterval = setInterval(() => {
|
||||||
|
starship.forwardSpeed += movementSpeedChange;
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
if (event.key === "ArrowDown" || event.key === "s" || event.key === "S") {
|
||||||
|
if (starship.forwardSpeed > 0) {
|
||||||
|
starship.forwardSpeed = 0;
|
||||||
|
}
|
||||||
|
starship.forwardSpeed -= movementSpeedChange;
|
||||||
|
clearInterval(forwardSpeedChangeInterval);
|
||||||
|
forwardSpeedChangeInterval = setInterval(() => {
|
||||||
|
starship.forwardSpeed -= movementSpeedChange;
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
if (event.key === " " && starship.canFire) {
|
||||||
|
fireTorpedo();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("click", () => {
|
||||||
|
if (!isGameRunning) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (starship.canFire) {
|
||||||
|
fireTorpedo();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("keyup", (event) => {
|
||||||
|
if (!isGameRunning) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.key === "ArrowLeft" || event.key === "a" || event.key === "A") {
|
||||||
|
clearInterval(rotationMomentumChangeInterval);
|
||||||
|
}
|
||||||
|
if (event.key === "ArrowRight" || event.key === "d" || event.key === "D") {
|
||||||
|
clearInterval(rotationMomentumChangeInterval);
|
||||||
|
}
|
||||||
|
if (event.key === "ArrowUp" || event.key === "w" || event.key === "W") {
|
||||||
|
clearInterval(forwardSpeedChangeInterval);
|
||||||
|
starship.forwardSpeed = 0;
|
||||||
|
}
|
||||||
|
if (event.key === "ArrowDown" || event.key === "s" || event.key === "S") {
|
||||||
|
clearInterval(forwardSpeedChangeInterval);
|
||||||
|
starship.forwardSpeed = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const tick = () => {
|
||||||
|
// Move starship
|
||||||
|
starship.rotation += starship.rotationMomentum;
|
||||||
|
const moveVector = {
|
||||||
|
x: (Math.cos(getDegToRad(starship.rotation)) || 0) * starship.forwardSpeed,
|
||||||
|
y: (Math.sin(getDegToRad(starship.rotation)) || 0) * starship.forwardSpeed,
|
||||||
|
};
|
||||||
|
const driftVector = {
|
||||||
|
x:
|
||||||
|
(Math.cos(getDegToRad(starship.driftDirection)) || 0) *
|
||||||
|
starship.driftSpeed,
|
||||||
|
y:
|
||||||
|
(Math.sin(getDegToRad(starship.driftDirection)) || 0) *
|
||||||
|
starship.driftSpeed,
|
||||||
|
};
|
||||||
|
const deltaXDrift = driftVector.x + moveVector.x;
|
||||||
|
const deltaYDrift = driftVector.y + moveVector.y;
|
||||||
|
if (starship.driftSpeed === 0) {
|
||||||
|
starship.driftDirection = starship.rotation;
|
||||||
|
} else {
|
||||||
|
starship.driftDirection =
|
||||||
|
getRadToDeg(Math.atan(deltaYDrift / deltaXDrift || 0)) +
|
||||||
|
(deltaXDrift < 0 ? 180 : 0);
|
||||||
|
}
|
||||||
|
starship.driftSpeed = (deltaXDrift ** 2 + deltaYDrift ** 2) ** 0.5;
|
||||||
|
starship.position.x +=
|
||||||
|
starship.driftSpeed * Math.cos(getDegToRad(starship.driftDirection)) || 0;
|
||||||
|
if (starship.position.x < 0) {
|
||||||
|
starship.position.x += ctx.canvas.width;
|
||||||
|
}
|
||||||
|
if (starship.position.x > ctx.canvas.width) {
|
||||||
|
starship.position.x -= ctx.canvas.width;
|
||||||
|
}
|
||||||
|
starship.position.y -=
|
||||||
|
starship.driftSpeed * Math.sin(getDegToRad(starship.driftDirection)) || 0;
|
||||||
|
if (starship.position.y < 0) {
|
||||||
|
starship.position.y += ctx.canvas.height;
|
||||||
|
}
|
||||||
|
if (starship.position.y > ctx.canvas.height) {
|
||||||
|
starship.position.y -= ctx.canvas.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move torpedoes
|
||||||
|
torpedoes.forEach((torpedo) => {
|
||||||
|
torpedo.position.x +=
|
||||||
|
torpedo.speed * Math.cos(getDegToRad(torpedo.direction)) || 0;
|
||||||
|
if (torpedo.position.x < 0) {
|
||||||
|
torpedo.position.x += ctx.canvas.width;
|
||||||
|
}
|
||||||
|
if (torpedo.position.x > ctx.canvas.width) {
|
||||||
|
torpedo.position.x -= ctx.canvas.width;
|
||||||
|
}
|
||||||
|
torpedo.position.y -=
|
||||||
|
torpedo.speed * Math.sin(getDegToRad(torpedo.direction)) || 0;
|
||||||
|
if (torpedo.position.y < 0) {
|
||||||
|
torpedo.position.y += ctx.canvas.height;
|
||||||
|
}
|
||||||
|
if (torpedo.position.y > ctx.canvas.height) {
|
||||||
|
torpedo.position.y -= ctx.canvas.height;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Move asteroids
|
||||||
|
asteroids.forEach((asteroid) => {
|
||||||
|
const asteroidSpeed = (3 - asteroid.size) * asteroidSpeedCoefficient;
|
||||||
|
const deltaPosition = {
|
||||||
|
x: asteroidSpeed * Math.cos(getDegToRad(asteroid.direction)) || 0,
|
||||||
|
y: asteroidSpeed * Math.sin(getDegToRad(asteroid.direction)) || 0,
|
||||||
|
};
|
||||||
|
asteroid.position.x += deltaPosition.x;
|
||||||
|
if (asteroid.position.x < 0) {
|
||||||
|
asteroid.position.x += ctx.canvas.width;
|
||||||
|
}
|
||||||
|
if (asteroid.position.x > ctx.canvas.width) {
|
||||||
|
asteroid.position.x -= ctx.canvas.width;
|
||||||
|
}
|
||||||
|
asteroid.position.y -= deltaPosition.y;
|
||||||
|
if (asteroid.position.y < 0) {
|
||||||
|
asteroid.position.y += ctx.canvas.height;
|
||||||
|
}
|
||||||
|
if (asteroid.position.y > ctx.canvas.height) {
|
||||||
|
asteroid.position.y -= ctx.canvas.height;
|
||||||
|
}
|
||||||
|
asteroid.rotation += asteroidSpeed;
|
||||||
|
if (asteroid.rotation > 360) {
|
||||||
|
asteroid.rotation -= 360;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
// Detect torpedo collisions
|
||||||
|
torpedoes.forEach((torpedo, torpedoIndex) => {
|
||||||
|
// Torpedo hitting asteroid
|
||||||
|
asteroids.forEach((asteroid) => {
|
||||||
|
let asteroidImage;
|
||||||
|
if (asteroid.size === 2) {
|
||||||
|
asteroidImage = asteroidBigImage;
|
||||||
|
}
|
||||||
|
if (asteroid.size === 1) {
|
||||||
|
asteroidImage = asteroidMediumImage;
|
||||||
|
}
|
||||||
|
if (asteroid.size === 0) {
|
||||||
|
asteroidImage = asteroidSmallImage;
|
||||||
|
}
|
||||||
|
if (getDistance(torpedo, asteroid) <= asteroidImage.naturalWidth / 2) {
|
||||||
|
torpedo.detonated = true;
|
||||||
|
asteroid.exploded = true;
|
||||||
|
explosions.push({
|
||||||
|
position: {
|
||||||
|
x: torpedo.position.x,
|
||||||
|
y: torpedo.position.y,
|
||||||
|
},
|
||||||
|
startedAt: now,
|
||||||
|
});
|
||||||
|
if (!starship.exploded) {
|
||||||
|
score++;
|
||||||
|
}
|
||||||
|
document.getElementById("score").innerHTML = score;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Torpedo hitting another torpedo
|
||||||
|
torpedoes.forEach((otherTorpedo, otherTorpedoIndex) => {
|
||||||
|
if (torpedoIndex !== otherTorpedoIndex) {
|
||||||
|
if (
|
||||||
|
getDistance(torpedo, otherTorpedo) <=
|
||||||
|
torpedoImage.naturalWidth / 2
|
||||||
|
) {
|
||||||
|
torpedo.detonated = true;
|
||||||
|
otherTorpedo.detonated = true;
|
||||||
|
explosions.push({
|
||||||
|
position: {
|
||||||
|
x: torpedo.position.x,
|
||||||
|
y: torpedo.position.y,
|
||||||
|
},
|
||||||
|
startedAt: now,
|
||||||
|
});
|
||||||
|
explosions.push({
|
||||||
|
position: {
|
||||||
|
x: otherTorpedo.position.x,
|
||||||
|
y: otherTorpedo.position.y,
|
||||||
|
},
|
||||||
|
startedAt: now,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Torpedo hitting starship
|
||||||
|
if (
|
||||||
|
!torpedo.detonated &&
|
||||||
|
!starship.exploded &&
|
||||||
|
now - torpedo.launchedAt > dangerousTorpedoTimeout
|
||||||
|
) {
|
||||||
|
if (getDistance(torpedo, starship) <= starshipImage.naturalWidth / 2) {
|
||||||
|
starship.exploded = true;
|
||||||
|
torpedo.detonated = true;
|
||||||
|
explosions.push({
|
||||||
|
position: {
|
||||||
|
x: starship.position.x,
|
||||||
|
y: starship.position.y,
|
||||||
|
},
|
||||||
|
startedAt: now,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
asteroids.forEach((asteroid) => {
|
||||||
|
if (!asteroid.exploded && !starship.exploded) {
|
||||||
|
// Asteroid hitting starship
|
||||||
|
let asteroidImage;
|
||||||
|
if (asteroid.size === 2) {
|
||||||
|
asteroidImage = asteroidBigImage;
|
||||||
|
}
|
||||||
|
if (asteroid.size === 1) {
|
||||||
|
asteroidImage = asteroidMediumImage;
|
||||||
|
}
|
||||||
|
if (asteroid.size === 0) {
|
||||||
|
asteroidImage = asteroidSmallImage;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
getDistance(asteroid, starship) <=
|
||||||
|
asteroidImage.naturalWidth / 2 + starshipImage.naturalWidth / 2
|
||||||
|
) {
|
||||||
|
starship.exploded = true;
|
||||||
|
explosions.push({
|
||||||
|
position: {
|
||||||
|
x: starship.position.x,
|
||||||
|
y: starship.position.y,
|
||||||
|
},
|
||||||
|
startedAt: now,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get rid of detonated torpedoes
|
||||||
|
torpedoes = torpedoes.filter((torpedo) => !torpedo.detonated);
|
||||||
|
|
||||||
|
// Get rid of invisible explosions
|
||||||
|
explosions = explosions.filter(
|
||||||
|
(explosion) => now - explosion.startedAt <= explosionDuration
|
||||||
|
);
|
||||||
|
|
||||||
|
asteroids = asteroids
|
||||||
|
.map((asteroid) => {
|
||||||
|
if (!asteroid.exploded) {
|
||||||
|
return asteroid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove exploded small asteroids
|
||||||
|
if (asteroid.size === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split exploded asteroids
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
size: asteroid.size - 1,
|
||||||
|
position: { x: asteroid.position.x, y: asteroid.position.y },
|
||||||
|
direction: getRandomDirection(),
|
||||||
|
rotation: getRandomDirection(),
|
||||||
|
exploded: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: asteroid.size - 1,
|
||||||
|
position: { x: asteroid.position.x, y: asteroid.position.y },
|
||||||
|
direction: getRandomDirection(),
|
||||||
|
rotation: getRandomDirection(),
|
||||||
|
exploded: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
})
|
||||||
|
.flat();
|
||||||
|
|
||||||
|
// Create new asteroid if the last one has exploded
|
||||||
|
if (asteroids.length === 0) {
|
||||||
|
asteroids = [
|
||||||
|
{
|
||||||
|
size: 2,
|
||||||
|
position: getRandomAsteroidPosition(starship),
|
||||||
|
direction: getRandomDirection(),
|
||||||
|
rotation: getRandomDirection(),
|
||||||
|
exploded: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Game over when starship has exploded
|
||||||
|
if (starship.exploded && !gameOver) {
|
||||||
|
gameOver = true;
|
||||||
|
clearInterval(rotationMomentumChangeInterval);
|
||||||
|
clearInterval(rotationMomentumChangeInterval);
|
||||||
|
clearInterval(forwardSpeedChangeInterval);
|
||||||
|
clearInterval(forwardSpeedChangeInterval);
|
||||||
|
setTimeout(() => {
|
||||||
|
isGameRunning = false;
|
||||||
|
clearInterval(clock);
|
||||||
|
document.getElementById("gameOver").classList.remove("hidden");
|
||||||
|
document.getElementById("finalScore").innerHTML = score;
|
||||||
|
document.getElementById("restart").tabIndex = 0;
|
||||||
|
document.getElementById("restart").focus();
|
||||||
|
}, explosionDuration * 2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const startGame = () => {
|
||||||
|
// Hide splash screen
|
||||||
|
document.getElementById("splash").classList.add("hidden");
|
||||||
|
document.getElementById("start").tabIndex = -1;
|
||||||
|
document.getElementById("start").blur();
|
||||||
|
document.getElementById("gameOver").classList.add("hidden");
|
||||||
|
document.getElementById("restart").tabIndex = -1;
|
||||||
|
document.getElementById("restart").blur();
|
||||||
|
|
||||||
|
// Reset score
|
||||||
|
score = 0;
|
||||||
|
document.getElementById("score").innerHTML = "0";
|
||||||
|
|
||||||
|
// Reset ship
|
||||||
|
starship = {
|
||||||
|
position: {
|
||||||
|
x: ctx.canvas.width / 2,
|
||||||
|
y: ctx.canvas.height / 2,
|
||||||
|
},
|
||||||
|
rotation: 90,
|
||||||
|
driftDirection: 0,
|
||||||
|
driftSpeed: 0,
|
||||||
|
rotationMomentum: 0,
|
||||||
|
forwardSpeed: 0,
|
||||||
|
canFire: true,
|
||||||
|
exploded: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reset torpedoes
|
||||||
|
torpedoes = [];
|
||||||
|
|
||||||
|
// Reset asteroids
|
||||||
|
asteroids = [
|
||||||
|
{
|
||||||
|
size: 2,
|
||||||
|
position: getRandomAsteroidPosition(starship),
|
||||||
|
direction: getRandomDirection(),
|
||||||
|
rotation: getRandomDirection(),
|
||||||
|
exploded: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
explosions = [];
|
||||||
|
|
||||||
|
// Start clock
|
||||||
|
isGameRunning = true;
|
||||||
|
isGamePaused = false;
|
||||||
|
gameOver = false;
|
||||||
|
clock = setInterval(tick, updateFrequency);
|
||||||
|
requestAnimationFrame(draw);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set up splash screen
|
||||||
|
document.getElementById("start").focus();
|
||||||
|
document.getElementById("start").addEventListener("click", (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
startGame();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set up game over screen
|
||||||
|
document.getElementById("restart").addEventListener("click", (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
startGame();
|
||||||
|
});
|
112
space-drifter/index.html
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Space Drifter</title>
|
||||||
|
<link rel="stylesheet" href="styles.css" />
|
||||||
|
<link rel="icon" href="assets/starship.svg" />
|
||||||
|
<meta property="og:title" content="Space Drifter" />
|
||||||
|
<meta property="og:type" content="article" />
|
||||||
|
<meta
|
||||||
|
property="og:image"
|
||||||
|
content="https://raw.githubusercontent.com/bence-toth/space-drifter/main/assets/space-drifter-cover.jpg"
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
property="og:url"
|
||||||
|
content="https://bence-toth.github.io/space-drifter/"
|
||||||
|
/>
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
content="A pretty darn difficult asteroid shooter game with realistic inertia and unconventional controls."
|
||||||
|
/>
|
||||||
|
<meta property="og:site_name" content="Space Drifter" />
|
||||||
|
<meta name="twitter:image:alt" content="Space Drifter" />
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="A pretty darn difficult asteroid shooter game with realistic inertia and unconventional controls."
|
||||||
|
/>
|
||||||
|
<meta name="keywords" content="Space Shooter, Game" />
|
||||||
|
<meta name="author" content="Bence A. Tóth" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="splash">
|
||||||
|
<div class="innerWrapper">
|
||||||
|
<h1>Space Drifter</h1>
|
||||||
|
<button id="start">
|
||||||
|
<span>Start game</span>
|
||||||
|
<div class="line top"></div>
|
||||||
|
<div class="line right"></div>
|
||||||
|
<div class="line bottom"></div>
|
||||||
|
<div class="line left"></div>
|
||||||
|
</button>
|
||||||
|
<div class="controls">
|
||||||
|
<h3>Controls</h3>
|
||||||
|
<dl>
|
||||||
|
<dt>Fire thrusters</dt>
|
||||||
|
<dd>
|
||||||
|
<div class="wasd">
|
||||||
|
<kbd>W</kbd>
|
||||||
|
<kbd>A</kbd>
|
||||||
|
<kbd>S</kbd>
|
||||||
|
<kbd>D</kbd>
|
||||||
|
</div>
|
||||||
|
<div class="wasd">
|
||||||
|
<kbd>↑</kbd>
|
||||||
|
<kbd>←</kbd>
|
||||||
|
<kbd>↓</kbd>
|
||||||
|
<kbd>→</kbd>
|
||||||
|
</div>
|
||||||
|
</dd>
|
||||||
|
<dt>Launch torpedo</dt>
|
||||||
|
<dd>
|
||||||
|
<kbd>Space</kbd>
|
||||||
|
<kbd>Mouse click</kbd>
|
||||||
|
</dd>
|
||||||
|
<dt>Pause/Resume</dt>
|
||||||
|
<dd>
|
||||||
|
<kbd>P</kbd>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
<footer>
|
||||||
|
<nav>
|
||||||
|
by
|
||||||
|
<a
|
||||||
|
href="https://github.com/bence-toth/space-drifter"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>Bence A. Tóth</a
|
||||||
|
>
|
||||||
|
</nav>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="paused" class="hidden">
|
||||||
|
<div class="innerWrapper">
|
||||||
|
<h2>Game paused</h2>
|
||||||
|
<p>Press <kbd>P</kbd> to resume</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="gameOver" class="hidden">
|
||||||
|
<div class="innerWrapper">
|
||||||
|
<h2>Game Over</h2>
|
||||||
|
<h3>Your score: <span id="finalScore"></span></h3>
|
||||||
|
<button id="restart" tabindex="-1">
|
||||||
|
<span>Restart game</span>
|
||||||
|
<div class="line top"></div>
|
||||||
|
<div class="line right"></div>
|
||||||
|
<div class="line bottom"></div>
|
||||||
|
<div class="line left"></div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="canvasWrapper">
|
||||||
|
<canvas id="game-canvas"></canvas>
|
||||||
|
<div id="score">0</div>
|
||||||
|
</div>
|
||||||
|
<script src="game.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
297
space-drifter/styles.css
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
@import url("https://fonts.googleapis.com/css2?family=Audiowide&display=swap");
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: "Audiowide", serif;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: hsl(0, 0%, 5%);
|
||||||
|
color: hsl(0, 0%, 95%);
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvasWrapper {
|
||||||
|
max-width: 95%;
|
||||||
|
max-height: 95%;
|
||||||
|
aspect-ratio: 16 / 9;
|
||||||
|
border: 2px solid hsl(0, 0%, 10%);
|
||||||
|
background-color: black;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
background-image: url(assets/stars.png);
|
||||||
|
background-position: center center;
|
||||||
|
background-size: 50vmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#score {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
color: white;
|
||||||
|
padding: 1.5vmin;
|
||||||
|
font-size: 3vmin;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#splash,
|
||||||
|
#gameOver,
|
||||||
|
#paused {
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-image: url(assets/stars.png);
|
||||||
|
background-position: center center;
|
||||||
|
background-size: 50vmin;
|
||||||
|
z-index: 1;
|
||||||
|
transition: opacity 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#splash.hidden,
|
||||||
|
#gameOver.hidden,
|
||||||
|
#paused.hidden {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.innerWrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 3vmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
#splash h1,
|
||||||
|
#gameOver h2,
|
||||||
|
#paused h2 {
|
||||||
|
font-size: 10vmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
#paused h2 {
|
||||||
|
animation: twinkle 2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes twinkle {
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
45% {
|
||||||
|
opacity: 0.3333;
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#gameOver h3 {
|
||||||
|
font-size: 3vmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
#paused p {
|
||||||
|
font-size: 3vmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 1.5vmin;
|
||||||
|
background-color: transparent;
|
||||||
|
color: inherit;
|
||||||
|
font-size: 1.5vmin;
|
||||||
|
outline: 0;
|
||||||
|
border: 2px solid hsl(0, 0%, 25%);
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
button span {
|
||||||
|
opacity: 0.5;
|
||||||
|
transition: opacity 0.5s;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
button .line {
|
||||||
|
position: absolute;
|
||||||
|
background-color: white;
|
||||||
|
transition: transform 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
button .top,
|
||||||
|
button .bottom {
|
||||||
|
width: calc(100% + 4px);
|
||||||
|
height: 2px;
|
||||||
|
transform: scaleX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
button .left,
|
||||||
|
button .right {
|
||||||
|
width: 2px;
|
||||||
|
height: calc(100% + 4px);
|
||||||
|
transform: scaleY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
button .top {
|
||||||
|
top: -2px;
|
||||||
|
left: -2px;
|
||||||
|
transform-origin: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
button .bottom {
|
||||||
|
bottom: -2px;
|
||||||
|
right: -2px;
|
||||||
|
transform-origin: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
button .left {
|
||||||
|
left: -2px;
|
||||||
|
bottom: -2px;
|
||||||
|
transform-origin: bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
button .right {
|
||||||
|
right: -2px;
|
||||||
|
top: -2px;
|
||||||
|
transform-origin: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:is(:hover, :focus, :active) .top,
|
||||||
|
button:is(:hover, :focus, :active) .bottom {
|
||||||
|
transform: scaleX(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
button:is(:hover, :focus, :active) .left,
|
||||||
|
button:is(:hover, :focus, :active) .right {
|
||||||
|
transform: scaleY(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
button:is(:hover, :focus, :active) span {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:is(:hover, :focus, :active) span,
|
||||||
|
button:is(:hover, :focus, :active) .line {
|
||||||
|
transition-delay: 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
margin-top: 5vmin;
|
||||||
|
border: 1px solid hsl(0, 0%, 50%);
|
||||||
|
background-color: hsl(0, 0%, 7.5%);
|
||||||
|
padding: 2vmin 4vmin 3vmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls h3 {
|
||||||
|
margin-bottom: 3vmin;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 3vmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
font-size: 2vmin;
|
||||||
|
gap: 3vmin 1.5vmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt,
|
||||||
|
dd {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1.5vmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wasd {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
grid-template-rows: 1fr 1fr;
|
||||||
|
gap: 0.5vmin;
|
||||||
|
grid-template-areas:
|
||||||
|
". w ."
|
||||||
|
"a s d";
|
||||||
|
}
|
||||||
|
|
||||||
|
.wasd kbd:nth-child(1) {
|
||||||
|
grid-area: w;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wasd kbd:nth-child(2) {
|
||||||
|
grid-area: a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wasd kbd:nth-child(3) {
|
||||||
|
grid-area: s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wasd kbd:nth-child(4) {
|
||||||
|
grid-area: d;
|
||||||
|
}
|
||||||
|
|
||||||
|
kbd {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
white-space: nowrap;
|
||||||
|
line-height: 1;
|
||||||
|
padding: 0.2em 0.4em;
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: hsl(0, 0%, 20%);
|
||||||
|
background-color: hsl(0, 0%, 90%);
|
||||||
|
border: 1px solid hsl(0, 0%, 80%);
|
||||||
|
border-radius: 0.25em;
|
||||||
|
box-shadow: 0 0.05em 0 hsla(0, 0%, 0%, 20%),
|
||||||
|
0 0.1em 0 hsla(0, 0%, 100%, 50%) inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
#splash footer {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
text-align: center;
|
||||||
|
padding: 2vmin;
|
||||||
|
color: hsl(0, 0%, 60%);
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
outline: 0;
|
||||||
|
transition: color 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover,
|
||||||
|
a:active,
|
||||||
|
a:focus {
|
||||||
|
color: hsl(0, 0%, 100%);
|
||||||
|
}
|
BIN
storage/bg1.jpg
Normal file
After Width: | Height: | Size: 462 KiB |
BIN
storage/car.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
storage/flappybird.png
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
storage/o.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
storage/paper1.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
storage/rock1.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
storage/scissor1.png
Normal file
After Width: | Height: | Size: 20 KiB |
85
storage/starship.svg
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="60"
|
||||||
|
height="60"
|
||||||
|
viewBox="0 0 15.875 15.875"
|
||||||
|
version="1.1"
|
||||||
|
id="svg5"
|
||||||
|
sodipodi:docname="starship-2.svg"
|
||||||
|
inkscape:version="1.1 (c4e8f9e, 2021-05-24)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview7"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
showguides="false"
|
||||||
|
inkscape:zoom="10.732997"
|
||||||
|
inkscape:cx="22.966559"
|
||||||
|
inkscape:cy="37.035323"
|
||||||
|
inkscape:window-width="1792"
|
||||||
|
inkscape:window-height="1067"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="25"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
id="path846"
|
||||||
|
style="fill:#666666;stroke-width:0.268942"
|
||||||
|
d="M 9.8934528,0 C 10.30926,0.27469322 10.583333,0.75084753 10.583333,1.2943116 v 7.6629967 c 0,0.854741 -0.6777342,1.5430967 -1.519287,1.5430967 H 6.8109538 c -0.8415528,0 -1.5192872,-0.6883557 -1.5192872,-1.5430967 V 1.2943116 c 0,-0.54048587 0.2711849,-1.01420861 0.6831624,-1.28958784 A 7.9374999,8.0618925 0 0 0 0,7.8131075 7.9374999,8.0618925 0 0 0 7.9374999,15.875 7.9374999,8.0618925 0 0 0 15.875,7.8131075 7.9374999,8.0618925 0 0 0 9.8934528,0 Z" />
|
||||||
|
<path
|
||||||
|
id="path846-2"
|
||||||
|
style="fill:#4d4d4d;stroke-width:0.268941"
|
||||||
|
d="M 11.770341,0.75964356 V 9.7451414 c 0,1.0379226 -0.835865,1.8732706 -1.8737875,1.8732706 H 5.9784463 c -1.0379223,0 -1.8737873,-0.835348 -1.8737873,-1.8732706 V 0.76274413 A 7.9374999,8.0618924 0 0 0 0,7.8129597 7.9374999,8.0618924 0 0 0 7.9374999,15.875 7.9374999,8.0618924 0 0 0 15.875,7.8129597 7.9374999,8.0618924 0 0 0 11.770341,0.75964356 Z" />
|
||||||
|
<path
|
||||||
|
id="path846-6"
|
||||||
|
style="fill:#ffcc00;stroke-width:0.268941"
|
||||||
|
d="M 9.8934528,0 C 10.304222,0.27136505 10.576275,0.7396087 10.582816,1.2748576 A 7.9374999,8.0618924 0 0 1 15.855879,8.3343749 7.9374999,8.0618924 0 0 0 15.875,7.8129597 7.9374999,8.0618924 0 0 0 9.8934528,0 Z M 5.974829,0.00465088 A 7.9374999,8.0618924 0 0 0 0,7.8129597 7.9374999,8.0618924 0 0 0 0.01963704,8.3410929 7.9374999,8.0618924 0 0 1 5.2921833,1.2779581 C 5.2976761,0.74438496 5.5670775,0.27720546 5.974829,0.00465088 Z" />
|
||||||
|
<circle
|
||||||
|
style="fill:#00ccff;stroke:#ffcc00;stroke-width:0.279613;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path1729"
|
||||||
|
cx="7.9375"
|
||||||
|
cy="13.49375"
|
||||||
|
r="0" />
|
||||||
|
<rect
|
||||||
|
style="fill:#4d4d4d;stroke:none;stroke-width:0.170662;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect3296"
|
||||||
|
width="1.6762948"
|
||||||
|
height="3.446121"
|
||||||
|
x="7.0993524"
|
||||||
|
y="7.5645933"
|
||||||
|
ry="0.55232006" />
|
||||||
|
<rect
|
||||||
|
style="fill:#333333;stroke:none;stroke-width:0.05941;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect3899"
|
||||||
|
width="1.3229166"
|
||||||
|
height="0.52916664"
|
||||||
|
x="7.2760415"
|
||||||
|
y="7.6729169"
|
||||||
|
ry="0.25653949" />
|
||||||
|
<ellipse
|
||||||
|
style="fill:#00ccff;stroke:#ffcc00;stroke-width:0.52916667;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path4376"
|
||||||
|
cx="7.9375"
|
||||||
|
cy="13.747297"
|
||||||
|
rx="2.4966176"
|
||||||
|
ry="1.7028677" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
BIN
storage/x.png
Normal file
After Width: | Height: | Size: 26 KiB |
73
style.css
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
body {
|
||||||
|
font-family: 'Arial', sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
background-color: #ff99cc; /* Light pink background */
|
||||||
|
color: #00CBF6; /* Light blue text */
|
||||||
|
text-align: center;
|
||||||
|
padding: 1em;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
background-color: #ff99cc; /* Light pink background */
|
||||||
|
color: #00CBF6; /* Light blue text */
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav ul {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav ul li {
|
||||||
|
display: inline;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #00CBF6; /* Light blue text */
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game {
|
||||||
|
border: 1px solid #ff99cc; /* Light pink border */
|
||||||
|
background-color: #ACE9F6; /* Light blue background */
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
background-color: #ff99cc; /* Light pink background */
|
||||||
|
color: #00CBF6; /* Light blue text */
|
||||||
|
text-align: center;
|
||||||
|
padding: 1em;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Girly font for headings and paragraphs */
|
||||||
|
h1, h2, p {
|
||||||
|
font-family: 'Pacifico', cursive;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popcorn {
|
||||||
|
max-width: 6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-video {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
BIN
tik-tak-toe/img/bg.jpg
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
tik-tak-toe/img/bg1.jpg
Normal file
After Width: | Height: | Size: 308 KiB |
BIN
tik-tak-toe/img/gameover.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
tik-tak-toe/img/o.png
Normal file
After Width: | Height: | Size: 390 KiB |
BIN
tik-tak-toe/img/x.png
Normal file
After Width: | Height: | Size: 345 KiB |
219
tik-tak-toe/index.htm
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>JS</title>
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<form id="Form" action="#">
|
||||||
|
<label>TIK TAK Jan</label>
|
||||||
|
<br />
|
||||||
|
<input class="p1" placeholder="Player-1" required="required" />
|
||||||
|
<input class="p2" placeholder="Player-2" required="required" />
|
||||||
|
<button onclick="Start()">Start</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
<div id="Tbl">
|
||||||
|
<!--<label>Game</label>-->
|
||||||
|
<section>
|
||||||
|
<p id="p1">user1</p>
|
||||||
|
<p id="say1"></p>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<p id="p2">user1</p>
|
||||||
|
<p id="say2"></p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div id="Finish">
|
||||||
|
<img src="img/gameover.png"/>
|
||||||
|
<button onclick="Startt()">AGAIN</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
let ply1;
|
||||||
|
let ply2;
|
||||||
|
let say1 = 0;
|
||||||
|
let say2 = 0;
|
||||||
|
let X = "<img src='img/x.png' >";
|
||||||
|
let O = "<img src='img/o.png' >";
|
||||||
|
/* let X="X";
|
||||||
|
let O="O";*/
|
||||||
|
let say = 1;
|
||||||
|
let M = [];
|
||||||
|
Massiv();
|
||||||
|
Qur();
|
||||||
|
function Start() {
|
||||||
|
document.getElementById("Tbl").style.display = "block";
|
||||||
|
document.getElementsByTagName("form")[0].style.display = "none";
|
||||||
|
ply1 = document.getElementsByTagName("input")[0].value;
|
||||||
|
ply2 = document.getElementsByTagName("input")[1].value;
|
||||||
|
document.getElementById("p1").innerHTML = `${ply1}`;
|
||||||
|
document.getElementById("p2").innerHTML = `${ply2}`;
|
||||||
|
document.getElementById("say1").innerHTML = say1;
|
||||||
|
document.getElementById("say2").innerHTML = say2;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
function Startt(){
|
||||||
|
document.getElementById("Finish").style.display = "none";
|
||||||
|
document.getElementsByTagName("form")[0].style.display = "block";
|
||||||
|
|
||||||
|
}
|
||||||
|
function Massiv() {
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
M[i] = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Qur() {
|
||||||
|
let tbl = "";
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
tbl += `<tr>`;
|
||||||
|
for (let j = 0; j < 3; j++) {
|
||||||
|
M[i][j] = M[i][j] == undefined ? "" : M[i][j];
|
||||||
|
tbl += `<td id="row_` + i + j + `" onclick="Tikla(${i},${j})">${M[i][j]}</td>`;
|
||||||
|
}
|
||||||
|
tbl += `</tr>`;
|
||||||
|
}
|
||||||
|
document.getElementsByTagName("table")[0].innerHTML = tbl;
|
||||||
|
}
|
||||||
|
function sil() {
|
||||||
|
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
for (let j = 0; j < 3; j++) {
|
||||||
|
M[i][j] = "";
|
||||||
|
|
||||||
|
document.getElementById("row_" + i + j).innerHTML = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
say=1;
|
||||||
|
console.log(say);
|
||||||
|
}
|
||||||
|
function Tikla(i, j) {
|
||||||
|
if (M[i][j] == "") {
|
||||||
|
if (say % 2 == 1) {
|
||||||
|
M[i][j] = X;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
M[i][j] = O;
|
||||||
|
}
|
||||||
|
say++;
|
||||||
|
setTimeout(Yoxla, 200);
|
||||||
|
Qur();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Yoxla() {
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
if (M[i][0] == M[i][1] && M[i][1] == M[i][2] && M[i][0] != "") {
|
||||||
|
if (M[i][0] == X) {
|
||||||
|
alert(`${ply1} you get 1 point`);
|
||||||
|
say1++;
|
||||||
|
document.getElementById("say1").innerHTML=say1;
|
||||||
|
sil();
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alert(`${ply2} you get 1 point`);
|
||||||
|
say2++;
|
||||||
|
document.getElementById("say2").innerHTML=say2;
|
||||||
|
sil();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
if (M[0][i] == M[1][i] && M[1][i] == M[2][i] && M[0][i] != "") {
|
||||||
|
if (M[0][i] == X) {
|
||||||
|
alert(`${ply1} you get 1 point`);
|
||||||
|
say1++;
|
||||||
|
document.getElementById("say1").innerHTML=say1;
|
||||||
|
sil();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alert(`${ply2} you get 1 point`);
|
||||||
|
say2++;
|
||||||
|
document.getElementById("say2").innerHTML=say2;
|
||||||
|
sil();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (M[0][0] == M[1][1] && M[1][1] == M[2][2] && M[0][0] != "") {
|
||||||
|
if (M[0][0] == X) {
|
||||||
|
alert(`${ply1} you get 1 point`);
|
||||||
|
say1++;
|
||||||
|
document.getElementById("say1").innerHTML=say1;
|
||||||
|
sil();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alert(`${ply2} you get 1 point`);
|
||||||
|
say2++;
|
||||||
|
document.getElementById("say2").innerHTML=say2;
|
||||||
|
sil();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (M[0][2] == M[1][1] && M[1][1] == M[2][0] && M[0][2] != "") {
|
||||||
|
if (M[0][2] == X) {
|
||||||
|
alert(`${ply1} you get 1 point`);
|
||||||
|
say1++;
|
||||||
|
document.getElementById("say1").innerHTML=say1;
|
||||||
|
sil();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alert(`${ply2} you get 1 point`);
|
||||||
|
say2++;
|
||||||
|
document.getElementById("say2").innerHTML=say2;
|
||||||
|
sil();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
for (let j = 0; j < 3; j++) {
|
||||||
|
if (M[0][0] != "" && M[0][1] != "" && M[0][2] != "" && M[1][0] != "" && M[1][1] != "" && M[1][2] != "" && M[2][0] != "" && M[2][1] != "" && M[2][2] != "") {
|
||||||
|
alert("None gets point!!");
|
||||||
|
sil();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(say1==3 )
|
||||||
|
{
|
||||||
|
say1==3;
|
||||||
|
alert(`${ply1} you are winner!`);
|
||||||
|
|
||||||
|
setTimeout(200);
|
||||||
|
// setTimeout(alert("OYUN BITDI"), 400);
|
||||||
|
document.getElementById("Tbl").style.display="none";
|
||||||
|
document.getElementById("Finish").style.display="flex";
|
||||||
|
document.getElementById("Finish").style.flexDirection="column";
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(say2==3)
|
||||||
|
{
|
||||||
|
say2==3;
|
||||||
|
alert(`${ply2} you are winner!`);
|
||||||
|
|
||||||
|
setTimeout(200);
|
||||||
|
// setTimeout(alert("OYUN BITDI"), 400);
|
||||||
|
document.getElementById("Tbl").style.display="none";
|
||||||
|
document.getElementById("Finish").style.display="flex";
|
||||||
|
document.getElementById("Finish").style.flexDirection="column";
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
164
tik-tak-toe/style.css
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
@import url('https://fonts.googleapis.com/css?family=Lobster&display=swap&subset=cyrillic,cyrillic-ext,latin-ext,vietnamese');
|
||||||
|
*
|
||||||
|
{
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: url(img/bg1.jpg);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
|
||||||
|
background-size: cover;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
background-color: #0e1f27;
|
||||||
|
height: 60px;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
display: none;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#say1 {
|
||||||
|
background-color: #0e1f27;
|
||||||
|
color: blanchedalmond;
|
||||||
|
font-size: 15px;
|
||||||
|
width: 100px;
|
||||||
|
height: 30px;
|
||||||
|
font-family: 'Lobster', cursive;
|
||||||
|
}
|
||||||
|
|
||||||
|
#say2 {
|
||||||
|
background-color: #0e1f27;
|
||||||
|
color: blanchedalmond;
|
||||||
|
font-size: 15px;
|
||||||
|
width: 100px;
|
||||||
|
height: 30px;
|
||||||
|
font-family: 'Lobster', cursive;
|
||||||
|
}
|
||||||
|
|
||||||
|
table,
|
||||||
|
td {
|
||||||
|
border: 5px solid black;
|
||||||
|
border-collapse: collapse;
|
||||||
|
background-color: #fa2f4d;
|
||||||
|
}
|
||||||
|
|
||||||
|
#Tbl label {
|
||||||
|
font-size: 45px;
|
||||||
|
font-family: 'Lobster', cursive;
|
||||||
|
margin-top: 50x;
|
||||||
|
color: lightcyan;
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#Tbl p {
|
||||||
|
background-color: #0e1f27;
|
||||||
|
color: blanchedalmond;
|
||||||
|
font-size: 25px;
|
||||||
|
font-family: 'Lobster', cursive;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 80px;
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
height: 100px;
|
||||||
|
width: 100px;
|
||||||
|
text-align: center;
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
#Finish
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#Finish img
|
||||||
|
{
|
||||||
|
width: 400px;
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
#Finish button{
|
||||||
|
text-align: center;
|
||||||
|
font-size: 30px;
|
||||||
|
height: 40px;
|
||||||
|
width: 250px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 15px;
|
||||||
|
outline: none;
|
||||||
|
background-color: firebrick;
|
||||||
|
margin-top: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: 'Lobster', cursive;
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
width: 500px;
|
||||||
|
height: 300px;
|
||||||
|
background-color: firebrick;
|
||||||
|
margin: auto;
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 0px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
form label {
|
||||||
|
font-family: 'Lobster', cursive;
|
||||||
|
font-size: 30px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
form input {
|
||||||
|
width: 200px;
|
||||||
|
margin-top: 50px;
|
||||||
|
height: 30px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 15px;
|
||||||
|
background-color: white;
|
||||||
|
color: black;
|
||||||
|
text-align: center;
|
||||||
|
outline: none;
|
||||||
|
font-family: 'Lobster', cursive;
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
form input::placeholder {
|
||||||
|
color: black;
|
||||||
|
text-align: center;
|
||||||
|
font-family: 'Lobster', cursive;
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
form button {
|
||||||
|
text-align: center;
|
||||||
|
height: 30px;
|
||||||
|
width: 150px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 15px;
|
||||||
|
outline: none;
|
||||||
|
color: firebrick;
|
||||||
|
margin-top: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: 'Lobster', cursive;
|
||||||
|
|
||||||
|
}
|