Demo
Code
Forest
- Razor
@page "/forest"
@inject NavigationManager NavigationManager
@inject IJSRuntime JSRuntime
<div id="wrapper">
<div id="content">
<div class="card text-center">
<h1>This is our <span style="color:green;"><b>Forest</b></span>.</h1>
<div class="header">
Score: <strong class="score">0</strong>
</div>
<div class="forest">
<div Id="crab"></div>
<div id="ant"></div>
</div>
</div>
</div>
</div>
@code {
protected override void OnAfterRender(bool firstRender) {
if (firstRender)
JSRuntime.InvokeVoidAsync("forest");
}
}
- Javascript
function forest() {
const scoreDisplay = document.querySelector(".score");
let score = 0;
let startGame = false;
function reset() {
score = 0;
startGame = true;
var ant = document.getElementById("ant");
if (ant.classList != "block") {
ant.classList.add("block");
}
scoreDisplay.innerHTML = score;
}
function jump() {
var crab = document.getElementById("crab");
var ant = document.getElementById("ant");
if (crab.classList != "jump") {
crab.classList.add("jump");
setTimeout(function () {
crab.classList.remove("jump");
}, 300);
}
}
function loop() {
let isAlive = setInterval(function () {
let crabTop = parseInt(window.getComputedStyle(crab).getPropertyValue("top"));
let antLeft = parseInt(window.getComputedStyle(ant).getPropertyValue("left"));
if (antLeft < 50 && antLeft > 0 && crabTop >= 140) {
location = "/ending-ant";
alert("Game Over");
}
}, 10);
}
document.addEventListener("keydown", function (event) {
if (!startGame) {
reset();
loop();
}
else {
scoreDisplay.innerHTML = score + 1;
jump();
score++;
if (score >= 10) {
location = "/road/intro";
alert("Clear");
}
}
})
}
- CSS
.forest {
width: 600px;
height: 200px;
border: 1px solid black;
margin: auto;
}
.forest > #crab {
width: 50px;
height: 50px;
background-image: url(../image/pixel_crab.png);
background-size: 50px 50px;
position: relative;
top: 150px;
}
.forest > #ant {
width: 20px;
height: 40px;
position: relative;
top: 110px;
left: 580px;
background-image: url(../image/pixel_ant.png);
background-size: 20px 40px;
}
.jump {
animation: jump 0.3s linear;
}
.block {
animation: block 1s infinite linear;
}
@keyframes jump {
0% {
top: 150px;
}
30% {
top: 130px;
}
50% {
top: 80px;
}
80% {
top: 130px;
}
100% {
top: 150px;
}
}
@keyframes block {
0% {
left: 580px;
}
100% {
left: -20px;
}
}
Road
- Razor
@page "/road"
@inject NavigationManager NavigationManager
@inject IJSRuntime JSRuntime
<div id="wrapper">
<div id="content">
<div class="card text-center">
<h1>This is the road <span style="color:red;"><b>humans made</b></span>.</h1>
<div class="road">
<div class="header">
Score: <strong class="score">0</strong>
</div>
<div class="grid">
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
</div>
</div>
</div>
</div>
</div>
@code {
protected override void OnAfterRender(bool firstRender) {
if(firstRender)
JSRuntime.InvokeVoidAsync("road");
}
}
- Javascript
function road() {
const cells = Array.from(document.querySelectorAll(".cell"));
const carCells = cells.slice(0, 30);
const crabCells = cells.slice(30);
const scoreDisplay = document.querySelector(".score");
let dropCount, speed, score;
reset();
document.addEventListener("keydown", e => {
if (!dropCount) {
startGame();
}
const crab = document.querySelector(".crab");
if (e.key == "ArrowRight" && crabCells.includes(crab.parentElement.nextElementSibling)) {
crab.parentElement.nextElementSibling.appendChild(crab);
}
if (e.key == "ArrowLeft" && crabCells.includes(crab.parentElement.previousElementSibling)) {
crab.parentElement.previousElementSibling.appendChild(crab);
}
})
function reset() {
dropCount = 0;
speed = 1000;
score = 0;
scoreDisplay.innerHTML = "0";
cells.forEach(cell => cell.innerHTML = "");
crabCells[1].innerHTML = '<div class="crab"></div>';
}
function startGame() {
reset();
loop();
}
function loop() {
let stopGame = false;
for (let i = carCells.length - 1; i >= 0; i--) {
const cell = carCells[i];
const nextCell = cells[i + 3];
const car = cell.children[0];
if (!car) {
continue;
}
nextCell.appendChild(car);
if (crabCells.includes(nextCell)) {
if (nextCell.querySelector(".crab")) {
stopGame = true;
}
else {
score++;
speed = Math.max(100, speed - 25);
scoreDisplay.innerHTML = score;
car.remove();
if (score >= 10) {
location = "/sun/intro";
alert("Clear");
}
}
}
}
if (dropCount % 2 == 0) {
const position = Math.floor(Math.random() * 3);
carCells[position].innerHTML = '<div class="car"></div>';
}
if (stopGame) {
location = "/ending-roadkill";
alert("Game Over");
}
else {
dropCount++;
setTimeout(loop, speed);
}
}
}
- CSS
.road > .header {
padding-bottom: 5px;
}
.road > .grid {
display: inline-grid;
grid-template-columns: repeat(3, 30px);
padding: 20px;
grid-gap: 5px;
border: 1px solid #ccc;
background: #222;
}
.road > .grid > .cell {
height: 30px;
}
.road > .grid > .cell > .car,
.road > .grid > .cell > .crab {
width: 100%;
height: 100%;
}
.road > .grid > .cell > .car {
background-image: url(../image/pixel_car.png);
background-size: 30px 30px;
}
.road > .grid > .cell > .crab {
background-image: url(../image/pixel_crab.png);
background-size: 30px 30px;
}
Sun
- Razor
@page "/sun"
@inject NavigationManager NavigationManager
@inject IJSRuntime JSRuntime
<div class="sun">
<p class="text">Loading...</p>
</div>
<style>
* {
margin: 0 !important;
padding: 0 !important;
}
</style>
@code {
protected override void OnAfterRender(bool firstRender) {
if (firstRender)
JSRuntime.InvokeVoidAsync("sun");
}
}
- Javascript
function sun() {
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.setClearColor(0xb7c3f3, 1);
const light = new THREE.AmbientLight(0xffffff);
scene.add(light);
const end_position = 3;
const start_position = -end_position;
const crab_start_position = start_position / 2;
const crab_end_position = -crab_start_position;
const text = document.querySelector(".text");
const TIME_LIMIT = 10;
let gameStat = false;
let isNight = true;
function createCube(size, positionX, rotY = 0, color = 0xfbc851) {
const geometry = new THREE.BoxGeometry(size.w, size.h, size.d);
const material = new THREE.MeshBasicMaterial({ color: color });
const cube = new THREE.Mesh(geometry, material);
cube.position.x = positionX;
cube.rotation.y = rotY;
scene.add(cube);
return cube;
}
camera.position.z = 5;
const loader = new THREE.GLTFLoader();
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
class Sphere {
constructor() {
loader.load("../models/sphere/scene.gltf", (gltf) => {
scene.add(gltf.scene);
gltf.scene.scale.set(.003, .003, .003);
gltf.scene.position.set(0, 0, 0);
this.sphere = gltf.scene;
});
}
lookDay() {
gsap.to(this.sphere.rotation, { x: -1.5, duration: .45 });
setTimeout(() => isNight = false, 450);
}
lookNight() {
gsap.to(this.sphere.rotation, { x: 1.5, duration: .45 });
setTimeout(() => isNight = true, 150);
}
async start() {
this.lookNight();
await delay((Math.random() * 1000) + 1000);
this.lookDay();
await delay((Math.random() * 750) + 750);
this.start();
}
}
function createTrack() {
createCube({ w: end_position * 2 + .2, h: 1.5, d: 1 }, 0, 0, 0xe5a716).position.z = -1;
createCube({ w: .2, h: 1.5, d: 1 }, end_position, -.35);
createCube({ w: .2, h: 1.5, d: 1 }, start_position, .15);
}
createTrack();
class Crab {
constructor() {
const geometry = new THREE.PlaneGeometry(.3, .3);
const loader = new THREE.TextureLoader();
const material = new THREE.MeshBasicMaterial({
map: loader.load("../image/pixel_crab.png"),
transparent: true
});
const plane = new THREE.Mesh(geometry, material);
plane.position.z = 3;
plane.position.x = crab_start_position;
scene.add(plane);
this.crab = plane;
this.crabInfo = {
positionX: crab_start_position,
velocity: 0
};
}
run() {
this.crabInfo.velocity = .01;
}
stop() {
gsap.to(this.crabInfo, { velocity: 0, duration: .1 });
}
check() {
if (this.crabInfo.velocity > 0 && !isNight) {
location = "/ending-burning";
alert("Game Over");
return;
}
if (this.crabInfo.positionX > crab_end_position - .2) {
location = "/rock/intro";
alert("Clear");
return;
}
}
update() {
this.check();
this.crabInfo.positionX += this.crabInfo.velocity;
this.crab.position.x = this.crabInfo.positionX;
}
}
const crab = new Crab();
const sphere = new Sphere();
async function init() {
await delay(500);
text.innerText = "Starting in 3";
await delay(500);
text.innerText = "Starting in 2";
await delay(500);
text.innerText = "Starting in 1";
await delay(500);
text.innerText = "Go!!!";
startGame();
}
function startGame() {
gameStat = true;
let progressBar = createCube({ w: 5, h: .1, d: 1 }, 0);
progressBar.position.y = 3.35;
gsap.to(progressBar.scale, { x: 0, duration: TIME_LIMIT, ease: "none" });
sphere.start();
setTimeout(() => {
if (gameStat) {
alert("Game Over");
location = "/ending-burning";
}
}, TIME_LIMIT * 1000);
}
init();
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
crab.update();
}
animate();
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
document.addEventListener('keydown', function (event) {
if (!gameStat) return;
crab.run();
})
document.addEventListener('keyup', function (event) {
crab.stop();
})
}
- CSS
.sun > .text {
position: fixed;
font-size: 50px;
font-family: Arial, Helvetica, sans-serif;
font-weight: bold;
top: 10px;
left: 50%;
text-shadow: 0 2px 5px rgba(0,0,0,.3);
transform: translateX(-50%);
}
Rock
- Razor
@page "/rock"
@inject NavigationManager NavigationManager
@inject IJSRuntime JSRuntime
<div id="wrapper">
<div id="content">
<div class="card text-center">
<div class="header">
<font size="5" id="score">Score</font> / <font size="5" id="heart">Life</font>
</div>
<div class="rock">
<div id="canvas"></div>
<hr id="line" align="left">
<img src="image/pixel_crab.png" style="width:100px;" />
<br />
<input id="text" placeholder="text" autofocus>
<button id="auth" class="btn btn-dark">Enter</button>
</div>
</div>
</div>
</div>
@code {
protected override void OnAfterRender(bool firstRender) {
if (firstRender)
JSRuntime.InvokeVoidAsync("rock");
}
}
- Javascript
function rock() {
var canvasWidth = 600;
var canvasHeigth = 380; // 키워드 생성되는 세로범위
var goal = 5;
var keyword = ['hanna', 'maggie', 'peter', 'justin', 'ilikim', 'meike'];
function heart_counter(heart) {
var result = "<font color=red>";
for (var x = 0; x < heart; ++x) {
result += "♥";
}
result += "</font>";
return result;
}
var keyword_cnt = 0;
var score = 0;
var heart = 5;
document.getElementById('score').innerHTML = "Score : " + score
document.getElementById('heart').innerHTML = "Life : " + heart_counter(heart);
function gamewin() {
clearInterval(setInterval1);
clearInterval(setInterval2);
location = "/beach/intro";
alert("Clear");
}
function remove_node(pRemoveEle) {
var vRemove = document.getElementById(pRemoveEle);
var vParent = vRemove.parentNode;
vParent.removeChild(vRemove);
vRemove = null;
}
function gameover(code) {
clearInterval(setInterval1);
clearInterval(setInterval2);
location = "/ending-angry";
alert("Game Over");
}
function random_speed(maxSpeed) {
return parseInt(Math.random() * maxSpeed) + 1;
}
function random_width() {
return parseInt(Math.random() * canvasWidth) + 50;
}
function keyword_rain() {
this.y = 0;
this.speed = random_speed(2);
this.node = document.createElement('h3');
this.node.id = keyword[keyword_cnt];
this.node.innerHTML = keyword[keyword_cnt++];
if (keyword_cnt >= keyword.length) {
clearInterval(setInterval1);
}
this.node.style.position = 'absolute';
this.node.style.left = random_width() + "px";
console.log(this.node.style.position.x);
document.getElementById('canvas').appendChild(this.node);
keyword_rain.prototype.move = function () {
if (this.y > canvasHeigth) {
this.node.remove();
this.y = this.speed = 0;
keyword.splice(keyword.indexOf(this.node.id), 1);
keyword_cnt -= 1;
heart -= 1;
document.getElementById('heart').innerHTML = "Life : " + heart_counter(heart);
if (heart < 1) gameover(1);
if (keyword.length == 0) gameover(2);
return;
}
this.y += this.speed;
this.node.style.top = this.y + 'px';
}
}
function keydown(keyCode) {
if (keyCode == "Enter") {
var text = document.getElementById('text');
if (keyword.indexOf(text.value) != -1) {
remove_node(text.value);
for (var i in game) {
if (game[i]['node'].id == text.value) {
game[i]['y'] = 0;
game[i]['speed'] = 0;
}
}
keyword.splice(keyword.indexOf(text.value), 1);
keyword_cnt -= 1;
score++;
document.getElementById('score').innerHTML = "Score : " + score;
}
text.value = "";
if (score >= goal) { gamewin(); return; }
if (keyword.length == 0) { gameover(2); return; }
}
return;
}
var game = [];
var setInterval1 = setInterval(function () {
game.push(new keyword_rain());
}, 1000);
var setInterval2 = setInterval(function () {
for (var x in game) { game[x].move(); }
}, 15);
document.addEventListener("keydown", e => {
keydown(e.key);
})
}
- CSS
.rock > #canvas {
background-color: #E3E3E3;
width: inherit;
height: 400px;
}
.rock > #line {
width: inherit;
border: 3px solid #EEEEEE;
}
.rock > #text {
font-size: 23px;
width: 300px;
height: 30px;
}
.rock > #auth {
width: 100px;
height: 30px;
}
Beach
@page "/beach"
@inject NavigationManager NavigationManager
@inject IJSRuntime JSRuntime
<div class="beach">
<div Id="game-board"></div>
</div>
<style>
* {
margin: 0 !important;
padding: 0 !important;
}
body {
min-height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
margin: 0;
background-color: black;
}
</style>
@code {
protected override void OnAfterRender(bool firstRender) {
if (firstRender)
JSRuntime.InvokeVoidAsync("beach");
}
}
- Javascript
function beach() {
let lastRenderTime = 0;
let gameOver = false;
const gameBoard = document.getElementById('game-board');
const GRID_SIZE = 21;
function update() {
updateCrab();
updateBaby();
checkDeath();
}
function draw(gameBoard) {
gameBoard.innerHTML = '';
drawCrab(gameBoard);
drawBaby(gameBoard);
}
function checkDeath() {
gameOver = outsideGrid(getCrabHead()) || crabIntersection();
}
const CRAB_SPEED = 2;
const crabBody = [{ x: 11, y: 11 }];
let newSegments = 0;
function updateCrab() {
addSegments();
const inputDirection = getInputDirection();
for (let i = crabBody.length - 2; i >= 0; i--) {
crabBody[i + 1] = { ...crabBody[i] };
}
crabBody[0].x += inputDirection.x;
crabBody[0].y += inputDirection.y;
}
function drawCrab(gameBoard) {
crabBody.forEach(segment => {
const crabElement = document.createElement('div');
crabElement.style.gridRowStart = segment.y;
crabElement.style.gridColumnStart = segment.x;
crabElement.classList.add('crab');
gameBoard.appendChild(crabElement);
})
}
function expandCrab(amount) {
newSegments += amount;
}
function onCrab(position, { ignoreHead = false } = {} ) {
return crabBody.some((segment, index) => {
if (ignoreHead && index == 0) return false;
return equalPositions(segment, position);
})
}
function equalPositions(pos1, pos2) {
return pos1.x == pos2.x && pos1.y == pos2.y;
}
function addSegments() {
for (let i = 0; i < newSegments; i++) {
crabBody.push({ ...crabBody[crabBody.length - 1] });
}
newSegments = 0;
}
function getCrabHead() {
return crabBody[0];
}
function crabIntersection() {
return onCrab(crabBody[0], { ignoreHead: true });
}
let baby = getRandomBabyPosition();
const EXPANSION_RATE = 1;
function updateBaby() {
if (onCrab(baby)) {
expandCrab(EXPANSION_RATE);
baby = getRandomBabyPosition();
}
}
function drawBaby(gameBoard) {
const babyElement = document.createElement('div');
babyElement.style.gridRowStart = baby.y;
babyElement.style.gridColumnStart = baby.x;
babyElement.classList.add('baby');
gameBoard.appendChild(babyElement);
}
function getRandomBabyPosition() {
let newBabyPosition
while (newBabyPosition == null || onCrab(newBabyPosition)) {
newBabyPosition = randomGridPosition();
}
return newBabyPosition;
}
function randomGridPosition() {
return {
x: Math.floor(Math.random() * GRID_SIZE) + 1,
y: Math.floor(Math.random() * GRID_SIZE) + 1
};
}
function outsideGrid(position) {
return (
position.x < 1 || position.x > GRID_SIZE || position.y < 1 || position.y > GRID_SIZE
);
}
let inputDirection = { x: 0, y: 0 };
let lastInputDirection = { x: 0, y: 0 };
function getInputDirection() {
lastInputDirection = inputDirection;
return inputDirection;
}
function animate() {
if (gameOver) {
location = "/ending-missing";
return alert("Game Over");
}
if (crabBody.length >= 10) {
location = "/ending-clear";
return alert("Clear");
}
requestAnimationFrame(animate);
let currentTime = new Date().getTime();
const secondsSinceLastRender = (currentTime - lastRenderTime) / 1000;
if (secondsSinceLastRender < 1 / CRAB_SPEED) return
lastRenderTime = currentTime;
update();
draw(gameBoard);
}
animate();
document.addEventListener('keydown', e => {
switch (e.key) {
case 'ArrowUp':
if (lastInputDirection.y != 0) break;
inputDirection = { x: 0, y: -1 };
break;
case 'ArrowDown':
if (lastInputDirection.y != 0) break;
inputDirection = { x: 0, y: 1 };
break;
case 'ArrowLeft':
if (lastInputDirection.x != 0) break;
inputDirection = { x: -1, y: 0 };
break;
case 'ArrowRight':
if (lastInputDirection.x != 0) break;
inputDirection = { x: 1, y: 0 };
break;
}
})
}
- CSS
.beach > #game-board {
background-color: #CCC;
width: 100vmin;
height: 100vmin;
display: grid;
grid-template-rows: repeat(21, 1fr);
grid-template-columns: repeat(21, 1fr);
}
.beach > #game-board > .crab {
background-image: url(../image/pixel_crab.png);
background-size: 35px 35px;
background-repeat: no-repeat;
background-position: center center;
}
.beach > #game-board > .baby {
background-image: url(../image/pixel_crab.png);
background-size: 20px 20px;
background-repeat: no-repeat;
background-position: center center;
}