Skip to content

Commit 5c923c0

Browse files
committed
✨ add episode 10
1 parent 7711f4b commit 5c923c0

15 files changed

+306
-0
lines changed

.DS_Store

0 Bytes
Binary file not shown.

episode_010/README.md

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
## Suggestions
2+
3+
* Dinosaur Jump Game
4+
* Retro Themed
5+
* Jump over Waffles
6+
* Power up with Cheesecake
7+
* Retro sound effects / music
8+
9+
* [ ] StatniPodporaVzdelavani - retrophilia
10+
* [ ] codico - Dinosaurs
11+
* [ ] DropManiaOfficial - Waffles
12+
* [ ] Cheesecakeman25 - cheesecake
13+
* [ ] FrozenSpray - game
14+
15+
## Credits
16+
17+
* Clouds - https://latenightcoffe.itch.io/2d-pixel-art-semi-realistic-clouds
18+
* Dinosaur - https://samuellee.itch.io/red-dinosaur-animated-pixel-art
19+
* Food - https://ghostpixxells.itch.io/pixelfood

episode_010/app.js

+187
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
const cloudsElement = document.querySelector('.clouds');
2+
const roadElement = document.querySelector('.road');
3+
const scoreElement = document.querySelector('.score-value');
4+
5+
function getRandomNumber(min, max) {
6+
return min + Math.floor(Math.random() * (max - min));
7+
}
8+
9+
const world = {
10+
gameOver: false,
11+
updateMs: 40,
12+
score: 0,
13+
objects: {
14+
clouds: [],
15+
roadLines: [],
16+
foods: [],
17+
dino: {
18+
isJumping: false,
19+
jumpTicks: 0,
20+
location: {
21+
y: -40,
22+
},
23+
element: document.querySelector('.dino'),
24+
},
25+
},
26+
};
27+
28+
function init() {
29+
let currentCloud = 1;
30+
const maxClouds = 4;
31+
for (let i = 0; i < 20; i += 1) {
32+
const cloudImage = document.createElement('img');
33+
cloudImage.src = `cloud-${currentCloud}.png`;
34+
cloudImage.classList.add('cloud');
35+
const cloud = {
36+
element: cloudImage,
37+
velocity: getRandomNumber(1, 3),
38+
scale: getRandomNumber(0.7, 1.4),
39+
location: {
40+
x: getRandomNumber(-20, 100),
41+
y: getRandomNumber(-20, 60),
42+
},
43+
};
44+
cloudImage.style.transform = `scale(${cloud.scale})`;
45+
world.objects.clouds.push(cloud);
46+
cloudImage.style.opacity = cloud.location.y + '%';
47+
cloudImage.style.top = cloud.location.y + '%';
48+
cloudImage.style.left = cloud.location.x + '%';
49+
cloudsElement.append(cloudImage);
50+
currentCloud += 1;
51+
if (currentCloud > maxClouds) {
52+
currentCloud = 1;
53+
}
54+
}
55+
for (let i = 0; i < 4; i += 1) {
56+
const roadLineElement = document.createElement('div');
57+
roadLineElement.classList.add('road-line');
58+
const roadLine = {
59+
element: roadLineElement,
60+
velocity: 1.5,
61+
location: {
62+
y: 40,
63+
x: (i * 20) + (20 * i),
64+
},
65+
};
66+
world.objects.roadLines.push(roadLine);
67+
roadLine.element.style.top = roadLine.location.y + '%';
68+
roadLine.element.style.left = roadLine.location.x + '%';
69+
roadElement.append(roadLineElement);
70+
}
71+
for (let i = 0; i < 5; i++) {
72+
const foodImage = document.createElement('img');
73+
foodImage.classList.add('food');
74+
foodImage.src = Math.random() > 0.5 ? 'waffle.png' : 'cheesecake.png';
75+
foodImage.style.position = 'absolute';
76+
const food = {
77+
element: foodImage,
78+
velocity: 1.5,
79+
location: {
80+
y: 5,
81+
x: 100 + (i * 100) + getRandomNumber(0, 50),
82+
},
83+
};
84+
food.element.style.top = food.location.y + '%';
85+
food.element.style.left = food.location.x + '%';
86+
roadElement.append(foodImage);
87+
world.objects.foods.push(food);
88+
}
89+
90+
draw();
91+
}
92+
93+
function draw() {
94+
world.objects.clouds.forEach((cloud) => {
95+
cloud.element.style.opacity = cloud.location.y + '%';
96+
cloud.element.style.left = cloud.location.x + '%';
97+
cloud.element.style.transform = `scale(${cloud.scale})`;
98+
});
99+
world.objects.roadLines.forEach((roadLine) => {
100+
roadLine.element.style.left = roadLine.location.x + '%';
101+
});
102+
world.objects.foods.forEach((food) => {
103+
food.element.style.left = food.location.x + '%';
104+
});
105+
if (world.objects.dino.isJumping && !world.objects.dino.element.src.endsWith('dino/jump.gif')) {
106+
world.objects.dino.element.src = 'dino/jump.gif';
107+
} else if (!world.objects.dino.isJumping && !world.objects.dino.element.src.endsWith('dino/walk.gif')) {
108+
world.objects.dino.element.src = 'dino/walk.gif';
109+
}
110+
world.objects.dino.element.style.top = world.objects.dino.location.y + '%';
111+
112+
if (!world.gameOver) {
113+
setTimeout(update, world.updateMs);
114+
} else {
115+
world.objects.dino.element.src = 'dino/jump.gif';
116+
world.objects.dino.element.style.transform = 'rotate(-90deg)';
117+
}
118+
119+
scoreElement.textContent = world.score;
120+
}
121+
122+
function update() {
123+
const dinoRect = world.objects.dino.element.getBoundingClientRect();
124+
const cloudsRect = cloudsElement.getBoundingClientRect();
125+
const roadRect = roadElement.getBoundingClientRect();
126+
world.objects.clouds.forEach((cloud) => {
127+
const cloudRect = cloud.element.getBoundingClientRect();
128+
if ((cloudRect.left + cloudRect.width) - 20 <= cloudsRect.left) {
129+
cloud.location.x = getRandomNumber(100, 120);
130+
cloud.location.y = getRandomNumber(-20, 60);
131+
cloud.scale = getRandomNumber(0.7, 1.4);
132+
} else {
133+
cloud.location.x -= cloud.velocity;
134+
}
135+
});
136+
world.objects.roadLines.forEach((roadLine) => {
137+
const roadLineRect = roadLine.element.getBoundingClientRect();
138+
if ((roadLineRect.left + roadLineRect.width) - 10 <= roadRect.left) {
139+
roadLine.location.x = 100;
140+
} else {
141+
roadLine.location.x -= roadLine.velocity;
142+
}
143+
});
144+
world.objects.foods.forEach((food, i) => {
145+
const foodRect = food.element.getBoundingClientRect();
146+
if (foodRect.left <= dinoRect.right - 80
147+
&& dinoRect.bottom - 80 > foodRect.top
148+
&& foodRect.left >= dinoRect.left + 20) {
149+
world.gameOver = true;
150+
}
151+
if ((foodRect.left + foodRect.width) <= roadRect.left) {
152+
const farthestFoodX = Math.max(...world.objects.foods.map((food) => food.location.x));
153+
food.location.x = farthestFoodX + 100 + getRandomNumber(0, 50);
154+
world.score += 1;
155+
} else {
156+
food.location.x -= food.velocity;
157+
}
158+
});
159+
160+
if (world.objects.dino.isJumping) {
161+
if (world.objects.dino.jumpTicks <= 12) {
162+
world.objects.dino.location.y -= 9;
163+
} else if (world.objects.dino.jumpTicks >= 16) {
164+
world.objects.dino.location.y += 9;
165+
}
166+
world.objects.dino.jumpTicks += 1;
167+
if (world.objects.dino.jumpTicks === 28) {
168+
world.objects.dino.isJumping = false;
169+
world.objects.dino.location.y = -40;
170+
world.objects.dino.jumpTicks = 0;
171+
world.updateMs *= 0.95;
172+
}
173+
}
174+
draw();
175+
}
176+
177+
init();
178+
179+
document.addEventListener('keydown', (event) => {
180+
if (event.code === 'ArrowUp') {
181+
world.objects.dino.isJumping = true;
182+
}
183+
});
184+
185+
document.addEventListener('click', () => {
186+
world.objects.dino.isJumping = true;
187+
});

episode_010/cheesecake.png

2.26 KB
Loading

episode_010/cloud-1.png

10.6 KB
Loading

episode_010/cloud-2.png

7.69 KB
Loading

episode_010/cloud-3.png

6.96 KB
Loading

episode_010/cloud-4.png

5.7 KB
Loading

episode_010/clouds.png

29.1 KB
Loading

episode_010/dino/jump.gif

17.9 KB
Loading

episode_010/dino/walk.gif

30.1 KB
Loading

episode_010/foods.png

95.4 KB
Loading

episode_010/index.html

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>RETRO DINO GAME</title>
8+
<link rel="stylesheet" href="styles.css">
9+
</head>
10+
<body>
11+
<main id="game">
12+
<div class="clouds">
13+
<div class="score">Score: <span class="score-value">0</span></div>
14+
</div>
15+
<div class="road">
16+
<img class="dino" src="dino/walk.gif">
17+
</div>
18+
</main>
19+
<script src="app.js"></script>
20+
</body>
21+
</html>

episode_010/styles.css

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
* {
2+
margin: 0;
3+
padding: 0;
4+
box-sizing: border-box;
5+
}
6+
7+
body {
8+
background: #1A1423;
9+
width: 100vw;
10+
height: 100vh;
11+
overflow: hidden;
12+
display: flex;
13+
justify-content: center;
14+
align-items: center;
15+
}
16+
17+
#game {
18+
width: 100vmin;
19+
height: 70vmin;
20+
outline: 10px solid black;
21+
overflow: hidden;
22+
}
23+
24+
.clouds {
25+
height: 70%;
26+
width: 100%;
27+
background: linear-gradient(#5465FF, #FEA82F 80%);
28+
position: relative;
29+
}
30+
31+
.road {
32+
height: 30%;
33+
width: 100%;
34+
background: #898989;
35+
position: relative;
36+
}
37+
38+
.score {
39+
font-family: 'Courier New', Courier, monospace;
40+
font-size: 3vmin;
41+
color: #1A1423;
42+
font-weight: bold;
43+
position: absolute;
44+
top: 1vmin;
45+
right: 1vmin;
46+
}
47+
48+
.cloud {
49+
width: 30vmin;
50+
image-rendering: pixelated;
51+
image-rendering: -moz-crisp-edges;
52+
image-rendering: crisp-edges;
53+
position: absolute;
54+
}
55+
56+
.dino {
57+
height: 120%;
58+
position: absolute;
59+
z-index: 100;
60+
/* outline: 10px solid red; */
61+
}
62+
63+
.road-line {
64+
width: 20%;
65+
height: 10%;
66+
background: #fffaf1;
67+
position: absolute;
68+
z-index: 1;
69+
}
70+
71+
.food {
72+
width: 15%;
73+
z-index: 2;
74+
image-rendering: pixelated;
75+
image-rendering: -moz-crisp-edges;
76+
image-rendering: crisp-edges;
77+
position: absolute;
78+
/* outline: 10px solid red; */
79+
}

episode_010/waffle.png

2.59 KB
Loading

0 commit comments

Comments
 (0)