Copy folder
This commit is contained in:
commit
f40d182e88
7 changed files with 343 additions and 0 deletions
66
README.md
Normal file
66
README.md
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
# A JS / Canvas workshop rövid összefoglalója
|
||||||
|
## Mi az a JavaScript?
|
||||||
|
|
||||||
|
+ Egy magasszintű, gyengén típusos, értelmezett nyelv.
|
||||||
|
+ A "böngészőben fut".
|
||||||
|
+ Változatos módon tudja befolyásolni az oldal állapotát.
|
||||||
|
+ A háttérben aszinkron módon képes szerverekkel kommunikálni ([AJAX](https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX))
|
||||||
|
+ A weboldal elemeit módosítani ([DOM manipulation](https://developer.mozilla.org/en-US/docs/Glossary/DOM))
|
||||||
|
+ Egy csomó HTML5-ös API-val kommunikálni:
|
||||||
|
+ [File](https://developer.mozilla.org/hu/docs/Web/API/File)
|
||||||
|
+ [HTMLMediaElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement)
|
||||||
|
+ **[Canvas](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API)**
|
||||||
|
+ etc.
|
||||||
|
+ És természetesen minden olyan dologra képes, ami egy magasszintű nyelvtől elvárható.
|
||||||
|
### [Kristóf nagyon jó JavaScript összefoglalója](https://github.com/kripod/schdesign-web-workshop/blob/master/notes/js.md)
|
||||||
|
### Egy nem annyira jó, viszont annál tömörebb összefoglaló
|
||||||
|
+ A konzolra kiírni (böngészőben **F12**-vel megnyitható) a ```console.log("szöveg");``` hívással lehet.
|
||||||
|
+ Alapvető szintaxisában olyan, mint a C.
|
||||||
|
+ Leszámítva a típusokat, helyette van ```let```, illetve ```const```.
|
||||||
|
+ Előbbi változó deklarálásra jó, utóbbi konstans inicializáláshoz.
|
||||||
|
+ *Még sok helyen lehet látni a ```var``` kulcsszót, ezt ne használjuk.*
|
||||||
|
+ Vannak ```class```-ok.
|
||||||
|
> Nincsenek attribútumok, láthatóság.
|
||||||
|
+ Van garbage collector.
|
||||||
|
+ A ```this``` bonyolult, de majd mindenki ráérez. [Bővebb infó róla](https://zellwk.com/blog/this).
|
||||||
|
+ Ezenfelül google, és előbb-utóbb mindent meg lehet tanulni.
|
||||||
|
|
||||||
|
Van egy csomó modern nyelvi elem benne, amikkel jobb és olvashatóbb kódot lehet írni. Ezeket célszerű használni, viszont nem kell egyből az összeset megtanulni. Először írjunk működő kódot, utána lehet refaktorálni, meg fancyzni.
|
||||||
|
|
||||||
|
**Ha ennél mélyebben is érdekel, akkor a fenti összefoglalót nézd meg, vagy olvass bele ebbe: [MDN JS](https://developer.mozilla.org/hu/docs/Web/JavaScript).**
|
||||||
|
|
||||||
|
## Canvas API
|
||||||
|
> [Kifejezetten jó dokumentáció](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API)
|
||||||
|
|
||||||
|
### Hogyan lehet használni?
|
||||||
|
|
||||||
|
+ A HTML bodyjához add hozzá: ```<canvas id="myCanvas"></canvas>```
|
||||||
|
+ JS-ben pedig:
|
||||||
|
```javascript
|
||||||
|
const canvas = document.getElementById('myCanvas');
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
```
|
||||||
|
+ Adjunk meg egy rajzoló színt: ```context.fillStyle = "rgba(255, 255, 0, 0.5)";```
|
||||||
|
+ Rajzoljunk egy téglalapot: ```context.fillRect(x0, y0, x1, y1);```
|
||||||
|
|
||||||
|
**További hasznos és szükséges információk: [MDN Canvas tutorial](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial)**
|
||||||
|
|
||||||
|
## Animáció
|
||||||
|
A következő kódrészletet célszerű alkalmazni.
|
||||||
|
```javascript
|
||||||
|
function nextFrame(timestamp) {
|
||||||
|
console.log(`Ennyi ideje fut a játék: ${timestamp}`)
|
||||||
|
|
||||||
|
//animáció logikája
|
||||||
|
|
||||||
|
requestAnimationFrame(nextFrame);
|
||||||
|
}
|
||||||
|
requestAnimationFrame(nextFrame);
|
||||||
|
```
|
||||||
|
> A ``` ` ``` (backticktől) ne ijedjünk meg, több infó róla: [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals).
|
||||||
|
|
||||||
|
> Természetesen a fenti ```function``` kulcsszó helyett egy [arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)t is használhattunk volna.
|
||||||
|
|
||||||
|
## A végére
|
||||||
|
Ezekről a témákról rengeteg kifejezetten jó forrás található az interneten. A JavaScriptről is írtak már egy pár könyvet. Ha valakit érdekel a téma, akkor minden lehetősége megvan, hogy elmélyedjen benne. Ez a fél oldal talán egy elfogadható kiindulási pontot ad, vagy ha azt nem, legalább egy kis plusz motivációt, hogy még többen ismerkedjenek meg a webnek ezen részével is.
|
||||||
|
# avoid
|
||||||
43
css/main.css
Normal file
43
css/main.css
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
html, body, canvas,#menuBox {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
text-align: center;
|
||||||
|
color: white;
|
||||||
|
font: 400 8vmin "Raleway", cursive;
|
||||||
|
}
|
||||||
|
canvas, button {
|
||||||
|
cursor: crosshair;
|
||||||
|
background-color: #a5402d;
|
||||||
|
}
|
||||||
|
p, button {
|
||||||
|
font-size: 4vmin;
|
||||||
|
margin-top: 4vmin;
|
||||||
|
}
|
||||||
|
#menuBox {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.box, button {
|
||||||
|
width: 33%;
|
||||||
|
border-radius: 4vmin;
|
||||||
|
}
|
||||||
|
.box {
|
||||||
|
padding: 4vmin;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
width: 60%;
|
||||||
|
padding: 1vmin;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
#endText {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
43
index.html
Normal file
43
index.html
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="hu">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||||
|
|
||||||
|
<title>Játék</title>
|
||||||
|
|
||||||
|
<meta name="theme-color" content="#A5402D" />
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css?family=Raleway"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<link rel="stylesheet" href="css/main.css" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="menuBox">
|
||||||
|
<div class="box">
|
||||||
|
<div id="startText">
|
||||||
|
<h1>Kerüld ki</h1>
|
||||||
|
<p>
|
||||||
|
a piros köröket a kurzorod (telefonon az ujjad) mozgatásával. Sok
|
||||||
|
sikert hozzá!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div id="endText">
|
||||||
|
<h1>Játék vége</h1>
|
||||||
|
<p id="endScore"></p>
|
||||||
|
</div>
|
||||||
|
<button id="startButton">Indítás</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<canvas id="canvas"></canvas>
|
||||||
|
|
||||||
|
<script src="js/CanvasHandler.js"></script>
|
||||||
|
<script src="js/InputHandler.js"></script>
|
||||||
|
<script src="js/vec2.js"></script>
|
||||||
|
<script src="js/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
40
js/CanvasHandler.js
Normal file
40
js/CanvasHandler.js
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
class CanvasHandler {
|
||||||
|
constructor(idOfCanvas) {
|
||||||
|
this.canvas = document.getElementById(idOfCanvas);
|
||||||
|
this.resize();
|
||||||
|
|
||||||
|
const handleResize = () => this.resize();
|
||||||
|
window.addEventListener("resize", handleResize);
|
||||||
|
|
||||||
|
this.context = this.canvas.getContext("2d");
|
||||||
|
}
|
||||||
|
|
||||||
|
resize() {
|
||||||
|
const rect = this.canvas.getBoundingClientRect();
|
||||||
|
this.canvas.width = rect.width;
|
||||||
|
this.canvas.height = rect.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
fillCanvas(color) {
|
||||||
|
this.context.fillStyle = color;
|
||||||
|
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawCircle([x, y], radius, color) {
|
||||||
|
this.context.beginPath();
|
||||||
|
this.context.arc(x, y, radius, 0, 2 * Math.PI, false);
|
||||||
|
this.context.fillStyle = color;
|
||||||
|
this.context.fill();
|
||||||
|
}
|
||||||
|
|
||||||
|
unitToPx(unit) {
|
||||||
|
return unit * Math.sqrt(this.width * this.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
get width() {
|
||||||
|
return this.canvas.width;
|
||||||
|
}
|
||||||
|
get height() {
|
||||||
|
return this.canvas.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
23
js/InputHandler.js
Normal file
23
js/InputHandler.js
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
class InputHandler {
|
||||||
|
constructor(idOfWatchedArea) {
|
||||||
|
const elem = document.getElementById(idOfWatchedArea);
|
||||||
|
|
||||||
|
const handleMouse = ({ offsetX, offsetY }) =>
|
||||||
|
this.setPointerPosition([offsetX, offsetY]);
|
||||||
|
const handleTouch = ({ touches }) =>
|
||||||
|
this.setPointerPosition([touches[0].clientX, touches[0].clientY]);
|
||||||
|
|
||||||
|
elem.addEventListener("mousemove", handleMouse);
|
||||||
|
elem.addEventListener("touchmove", handleTouch);
|
||||||
|
|
||||||
|
this.pointerPosition = [0, 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
setPointerPosition(newPosition) {
|
||||||
|
this.pointerPosition = newPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
get position() {
|
||||||
|
return this.pointerPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
115
js/main.js
Normal file
115
js/main.js
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
const enemySpawnFrequency = 2.5;
|
||||||
|
|
||||||
|
const canvasHandler = new CanvasHandler("canvas");
|
||||||
|
const inputHandler = new InputHandler("canvas");
|
||||||
|
|
||||||
|
let game;
|
||||||
|
function newGame() {
|
||||||
|
canvasHandler.fillCanvas("black");
|
||||||
|
game = new Game();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("startButton").addEventListener("click", newGame);
|
||||||
|
|
||||||
|
class Circle {
|
||||||
|
constructor(position, color, velocity, target, size) {
|
||||||
|
this.position = position;
|
||||||
|
this.color = color;
|
||||||
|
this.velocity = velocity;
|
||||||
|
this.target = target;
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
move(deltaTime) {
|
||||||
|
if (deltaTime > 0) {
|
||||||
|
const maxDistance = this.velocity * deltaTime;
|
||||||
|
const deltaPosition = subtract(this.target.position, this.position);
|
||||||
|
|
||||||
|
this.position = add(this.position, limit(deltaPosition, maxDistance));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draw(canvasHandler) {
|
||||||
|
canvasHandler.drawCircle(this.position, this.size, this.color);
|
||||||
|
}
|
||||||
|
isTouching(other) {
|
||||||
|
return magnitude(subtract(this.position, other.position)) < 2 * this.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Game {
|
||||||
|
constructor() {
|
||||||
|
this.player = new Circle(
|
||||||
|
[0.5 * canvasHandler.width, 0.5 * canvasHandler.height],
|
||||||
|
"#FFC07F",
|
||||||
|
canvasHandler.unitToPx(0.0002),
|
||||||
|
inputHandler,
|
||||||
|
canvasHandler.unitToPx(0.01)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.circleHolder = [this.player];
|
||||||
|
this.spawnInterval = 1000 / enemySpawnFrequency;
|
||||||
|
this.previousSpawn = this.previousTimestamp = 0;
|
||||||
|
this.score = 0;
|
||||||
|
|
||||||
|
this.menuBox = document.getElementById("menuBox").style;
|
||||||
|
document.getElementById("startText").style.display = this.menuBox.display =
|
||||||
|
"none";
|
||||||
|
|
||||||
|
this.isActive = true;
|
||||||
|
window.requestAnimationFrame(this.nextFrame.bind(this));
|
||||||
|
}
|
||||||
|
nextFrame(timestamp) {
|
||||||
|
if (this.isActive) {
|
||||||
|
canvasHandler.fillCanvas("rgba(165, 64, 45, 0.1)");
|
||||||
|
this.spawnEnemyIfNeeded(timestamp);
|
||||||
|
this.moveCircles(timestamp);
|
||||||
|
window.requestAnimationFrame(this.nextFrame.bind(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spawnEnemyIfNeeded(timestamp) {
|
||||||
|
if (timestamp - this.previousSpawn > this.spawnInterval) {
|
||||||
|
this.circleHolder.push(
|
||||||
|
new Circle(
|
||||||
|
[
|
||||||
|
Math.random() > 0.5 ? -10 : 1.05 * canvasHandler.width,
|
||||||
|
Math.random() * canvasHandler.height
|
||||||
|
],
|
||||||
|
"#F15156",
|
||||||
|
canvasHandler.unitToPx(0.0001),
|
||||||
|
this.player,
|
||||||
|
canvasHandler.unitToPx(0.01)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.previousSpawn = timestamp;
|
||||||
|
this.score++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
moveCircles(timestamp) {
|
||||||
|
const deltaTime = this.getDeltaTime(timestamp);
|
||||||
|
for (let i = 0; i < this.circleHolder.length; i++) {
|
||||||
|
this.circleHolder[i].move(deltaTime);
|
||||||
|
this.circleHolder[i].draw(canvasHandler);
|
||||||
|
|
||||||
|
for (let j = i + 1; j < this.circleHolder.length; j++) {
|
||||||
|
if (this.circleHolder[i].isTouching(this.circleHolder[j])) {
|
||||||
|
if (this.circleHolder[i] == this.player) this.showEndScreen();
|
||||||
|
else {
|
||||||
|
this.circleHolder.splice(i, 1);
|
||||||
|
this.circleHolder.splice(j - 1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getDeltaTime(timestamp) {
|
||||||
|
const tempPreviousTime = this.previousTime;
|
||||||
|
this.previousTime = timestamp;
|
||||||
|
return timestamp - tempPreviousTime;
|
||||||
|
}
|
||||||
|
showEndScreen() {
|
||||||
|
document.getElementById("endText").style.display = "block";
|
||||||
|
document.getElementById("endScore").innerHTML = `Pontszámod: ${this.score}`;
|
||||||
|
this.menuBox.display = "flex";
|
||||||
|
this.isActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
js/vec2.js
Normal file
13
js/vec2.js
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
const magnitude = ([x, y]) => Math.sqrt(x * x + y * y);
|
||||||
|
|
||||||
|
const add = ([x1, y1], [x2, y2]) => [x1 + x2, y1 + y2];
|
||||||
|
|
||||||
|
const subtract = ([x1, y1], [x2, y2]) => [x1 - x2, y1 - y2];
|
||||||
|
|
||||||
|
const limit = ([x, y], maxMagnitude) => {
|
||||||
|
const m = magnitude([x, y]);
|
||||||
|
if (m <= maxMagnitude) return [x, y];
|
||||||
|
|
||||||
|
const scalingFactor = maxMagnitude / m;
|
||||||
|
return [x * scalingFactor, y * scalingFactor];
|
||||||
|
};
|
||||||
Loading…
Add table
Add a link
Reference in a new issue