factor to nodejs application
This commit is contained in:
parent
8cb80b9cbe
commit
b237b857c7
10 changed files with 764 additions and 0 deletions
67
static/assets/head.svg
Normal file
67
static/assets/head.svg
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="61.553852"
|
||||
height="183.03311"
|
||||
viewBox="0 0 61.553852 183.03311"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
|
||||
sodipodi:docname="head.svg"
|
||||
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="namedview1"
|
||||
pagecolor="#000000"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="px"
|
||||
inkscape:zoom="2.9077441"
|
||||
inkscape:cx="20.806508"
|
||||
inkscape:cy="88.384669"
|
||||
inkscape:window-width="1860"
|
||||
inkscape:window-height="1004"
|
||||
inkscape:window-x="30"
|
||||
inkscape:window-y="46"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<marker
|
||||
style="overflow:visible"
|
||||
id="Triangle"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto-start-reverse"
|
||||
inkscape:stockid="Triangle arrow"
|
||||
markerWidth="1"
|
||||
markerHeight="1"
|
||||
viewBox="0 0 1 1"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always"
|
||||
preserveAspectRatio="xMidYMid">
|
||||
<path
|
||||
transform="scale(0.5)"
|
||||
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
|
||||
d="M 5.77,0 -2.88,5 V -5 Z"
|
||||
id="path135" />
|
||||
</marker>
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-19.223075,68.033118)">
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke:#fcf9f9;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Triangle);paint-order:stroke fill markers"
|
||||
d="M 50,110 V -32.52237"
|
||||
id="path1" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
72
static/assets/player.svg
Normal file
72
static/assets/player.svg
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="120"
|
||||
height="120"
|
||||
viewBox="0 0 120 120"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
|
||||
sodipodi:docname="player.svg"
|
||||
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="namedview1"
|
||||
pagecolor="#000000"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="px"
|
||||
inkscape:zoom="8.2243423"
|
||||
inkscape:cx="66.023517"
|
||||
inkscape:cy="55.080392"
|
||||
inkscape:window-width="1860"
|
||||
inkscape:window-height="1004"
|
||||
inkscape:window-x="30"
|
||||
inkscape:window-y="46"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs1" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(10,10)">
|
||||
<circle
|
||||
style="fill:#000000;fill-opacity:1;stroke:#fcf9f9;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
id="path1"
|
||||
cx="50"
|
||||
cy="50"
|
||||
r="50" />
|
||||
<path
|
||||
id="circle1"
|
||||
style="fill:#ffffff;stroke:#fcf9f9;stroke-width:3.98197;stroke-linecap:round;stroke-linejoin:round;paint-order:stroke fill markers"
|
||||
d="m 42.827076,40.730564 c -0.530179,8.374653 -2.920163,15.194007 -6.522366,15.194007 -3.602203,0 -6.640889,-6.803426 -6.522366,-15.194007 0.11532,-8.163806 13.616818,-9.036609 13.044732,0 z"
|
||||
sodipodi:nodetypes="ssss" />
|
||||
<path
|
||||
id="ellipse1"
|
||||
style="fill:#ffffff;stroke:#fcf9f9;stroke-width:3.98197;stroke-linecap:round;stroke-linejoin:round;paint-order:stroke fill markers"
|
||||
d="m 70.217656,40.546146 c 0,8.391418 -2.920163,15.194007 -6.522366,15.194007 -3.602203,0 -6.522366,-6.802589 -6.522366,-15.194007 0,-8.391418 3.092117,-16.931967 6.694321,-16.931967 3.602203,0 6.350411,8.540549 6.350411,16.931967 z"
|
||||
sodipodi:nodetypes="sssss" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#fcf9f9;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;paint-order:stroke fill markers"
|
||||
d="M 25.854918,30.643384 H 47.629179"
|
||||
id="path2" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#fcf9f9;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;paint-order:stroke fill markers"
|
||||
d="m 53.246967,18.854004 c 1.048608,-8.377641 -1.071223,-7.088082 11.233085,-7.805733 11.451296,-0.667899 9.895156,3.566952 10.541176,7.805733"
|
||||
id="path3"
|
||||
sodipodi:nodetypes="csc" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#fcf9f9;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;paint-order:stroke fill markers"
|
||||
d="M 31.743312,69.350998 H 64.911025"
|
||||
id="path4" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.2 KiB |
64
static/index.css
Normal file
64
static/index.css
Normal file
|
@ -0,0 +1,64 @@
|
|||
:root {
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
color: rgb(44, 41, 53);
|
||||
}
|
||||
|
||||
section {
|
||||
max-width: 90vw;
|
||||
width: 800px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
background: rgb(255, 255, 255);
|
||||
border: solid rgb(200, 200, 200) 2px;
|
||||
border-radius: 10px;
|
||||
min-height: 500px;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
text-align: center;
|
||||
margin: 10px;
|
||||
margin-bottom: 0;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.message span {
|
||||
display: block;
|
||||
text-align: center;
|
||||
color: rgb(255, 255, 255);
|
||||
font-weight: bold;
|
||||
font-size: 50px;
|
||||
}
|
||||
|
||||
.ui-text {
|
||||
white-space: pre-wrap;
|
||||
font-weight: bold;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#canvas {
|
||||
width: 768px;
|
||||
height: 768px;
|
||||
/*image-rendering: pixelated;*/
|
||||
background: rgb(63, 63, 71);
|
||||
}
|
||||
|
||||
section#main {
|
||||
width: 1024px;
|
||||
}
|
||||
|
||||
@media (max-width: 1920px) {
|
||||
#canvas {
|
||||
width: min(512px, 90vw);
|
||||
height: min(512px, 90vw);
|
||||
}
|
||||
}
|
27
static/index.html
Normal file
27
static/index.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<link rel='stylesheet' href='index.css'>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<section id='main'>
|
||||
<h1>UniButton</h1>
|
||||
<p>The <b>left mouse button</b> is the only input. No keyboard, moving the mouse, or anything else.</p>
|
||||
<p>Click to launch... figure out the rest of the combos yourself.</p>
|
||||
<p><i>Created by <a href='https://zenoverse.net/'>Onez</a>. Join our <a
|
||||
href='https://discord.gg/EpsRZrHswBu'>Discord</a>!</i></p>
|
||||
<div>
|
||||
<canvas id='canvas'></canvas>
|
||||
</div>
|
||||
<div class='ui-text'>
|
||||
placeholder
|
||||
</div>
|
||||
</section>
|
||||
<script src='js/player.js'></script>
|
||||
<script src='js/index.js'></script>
|
||||
</body>
|
||||
|
||||
</html>
|
99
static/js/index.js
Normal file
99
static/js/index.js
Normal file
|
@ -0,0 +1,99 @@
|
|||
const cs = 1024;
|
||||
const assets = [
|
||||
'assets/player.svg',
|
||||
'assets/head.svg',
|
||||
];
|
||||
|
||||
function Game() {
|
||||
let assetsIn = {};
|
||||
|
||||
for (let asset in assets) {
|
||||
assetsIn[asset] = new Image();
|
||||
assetsIn[asset].src = assets[asset];
|
||||
}
|
||||
|
||||
let canvas = document.querySelector("#canvas");
|
||||
let player = new Player(true);
|
||||
let entities = [player];
|
||||
|
||||
for (let i = 0; i < 50; i++) {
|
||||
entities.push(new Player())
|
||||
}
|
||||
|
||||
canvas.width = canvas.height = cs;
|
||||
|
||||
this.canvas = canvas;
|
||||
this.ctx = canvas.getContext("2d");
|
||||
this.assetsIn = assetsIn;
|
||||
this.player = player;
|
||||
this.entities = entities;
|
||||
}
|
||||
|
||||
Game.prototype.main = function () {
|
||||
let { entities, player } = this;
|
||||
|
||||
if (player.health <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let ent of entities) {
|
||||
ent.handleTick(this);
|
||||
}
|
||||
}
|
||||
|
||||
// todo: move into its own file
|
||||
Game.prototype.render = function () {
|
||||
let { ctx, assetsIn, entities, player } = this;
|
||||
|
||||
ctx.clearRect(0, 0, cs, cs);
|
||||
|
||||
ctx.save();
|
||||
|
||||
ctx.translate(player.camera.x + cs / 2, player.camera.y + cs / 2);
|
||||
|
||||
for (let ent of entities) {
|
||||
ctx.save();
|
||||
|
||||
ctx.translate(ent.pos.x, ent.pos.y);
|
||||
ctx.rotate(ent.rot);
|
||||
ctx.drawImage(assetsIn[1], -64 / 2, -128, 64, 128);
|
||||
|
||||
ctx.restore();
|
||||
|
||||
ctx.drawImage(assetsIn[0], ent.pos.x - 64 / 2, ent.pos.y - 64 / 2, 64, 64);
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
|
||||
if (player.health <= 0) {
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.5)';
|
||||
ctx.fillRect(0,0,cs,cs);
|
||||
ctx.fillStyle = 'rgb(255,255,255)';
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.font = "bold 48px sans-serif";
|
||||
ctx.fillText('You died! Click to respawn',cs/2,cs/2);
|
||||
}
|
||||
}
|
||||
|
||||
Game.prototype.ui = function() {
|
||||
document.querySelector('.ui-text').textContent = `HP: ${this.player.health}`
|
||||
}
|
||||
|
||||
Game.prototype.click = function () {
|
||||
let { player } = this;
|
||||
|
||||
if (player.health <= 0) {
|
||||
game = new Game();
|
||||
} else {
|
||||
player.bump();
|
||||
}
|
||||
}
|
||||
|
||||
var game = new Game();
|
||||
|
||||
setInterval(function () { game.main() }, 1000 / 60);
|
||||
setInterval(function () { game.render() }, 1000 / 60);
|
||||
setInterval(function () { game.ui() }, 1000 / 10);
|
||||
|
||||
game.canvas.onclick = () => game.click();
|
71
static/js/player.js
Normal file
71
static/js/player.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
function Player(you) {
|
||||
let pos = { x: Math.random() * 5000 - 50, y: Math.random() * 5000 - 50 };
|
||||
let camera = { x: -pos.x, y: -pos.y };
|
||||
let vel = { x: 0, y: 0 };
|
||||
|
||||
this.camera = camera;
|
||||
this.pos = pos;
|
||||
this.vel = vel;
|
||||
this.rot = 0;
|
||||
this.dir = 1;
|
||||
this.ticks = 0;
|
||||
|
||||
this.health = 100;
|
||||
|
||||
this.you = you;
|
||||
}
|
||||
|
||||
Player.prototype.bump = function () {
|
||||
let player = this;
|
||||
|
||||
if (player.ticks < 10) {
|
||||
player.dir *= -1;
|
||||
}
|
||||
|
||||
player.vel.x *= 0.3;
|
||||
player.vel.y *= 0.3;
|
||||
|
||||
player.vel.x += Math.sin(player.rot) * 12;
|
||||
player.vel.y -= Math.cos(player.rot) * 12;
|
||||
|
||||
player.ticks = 0;
|
||||
}
|
||||
|
||||
Player.prototype.handleTick = function(game) {
|
||||
let { player } = game;
|
||||
|
||||
let ent = this;
|
||||
|
||||
ent.pos.x += ent.vel.x;
|
||||
ent.pos.y += ent.vel.y;
|
||||
|
||||
ent.vel.x *= 0.9;
|
||||
ent.vel.y *= 0.9;
|
||||
|
||||
ent.rot += 0.03 * ent.dir;
|
||||
ent.rot = ent.rot % (Math.PI * 10);
|
||||
|
||||
ent.camera.x = -ent.pos.x * 0.1 + ent.camera.x * 0.9;
|
||||
ent.camera.y = -ent.pos.y * 0.1 + ent.camera.y * 0.9;
|
||||
|
||||
ent.ticks++;
|
||||
|
||||
let dist = ((ent.pos.x - player.pos.x) ** 2) + ((ent.pos.y - player.pos.y) ** 2);
|
||||
|
||||
let dp = (Math.sin(ent.rot) * (ent.pos.x - player.pos.x))
|
||||
- (Math.cos(ent.rot) * (ent.pos.y - player.pos.y));
|
||||
|
||||
dp /= dist;
|
||||
|
||||
dp *= 10;
|
||||
|
||||
if (ent.you) return;
|
||||
|
||||
if (Math.random() < -dp && Math.random() > 3 / (ent.ticks+2)) {
|
||||
ent.bump();
|
||||
}
|
||||
|
||||
if (Math.sqrt(dist) < 96 / 2) {
|
||||
player.health --;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue