Who's that Pokemon? Identify the Pokemon Game| HTML, CSS, JS
IDENTIFY THE POKEMON GAME. USING HTML, CSS, JS
Hey there guys, let me give you a small concept of how it works. Actually this works in such a way that you can select the type of trainer as you wish and at each level you will be provided with image of a pokemon and some options so that you can identify them easily. It is just a childish game. But it took me of around 2-3 hrs continuous effort on codepen. Made it as a self challenge. Ok enjoy yourself and comment your suggestions...
DEMO:
Now let's jump right into the coding part. Here my ingredients are HTML, CSS(SCSS) and JavaScript(Babel).
HTML:
<div id="app"> <div :class="{'poke-classic': classic}" class="container" > <transition name="animate-section"> <section v-if="!isPlaying && !isDone" class="poke-section" > <h2>What type of trainer are you?</h2> <div class="poke-intro-trainer"> <div class="poke-ball"></div> <img :class="{active: trainerHovered === 'classic'}" class="poke-trainer-img poke-trainer-img-classic" src="https://raw.githubusercontent.com/tiffachoo/pokesprites/master/trainers/red-rb.png" alt="Trainer red" > <img :class="{active: trainerHovered === 'master'}" class="poke-trainer-img poke-trainer-img-master" src="https://raw.githubusercontent.com/tiffachoo/pokesprites/master/trainers/red-sm.png" alt="Trainer red again" > </div> <button class="button spacer" @click="startGame(151)" @mouseover="trainerHover('classic')" @mouseout="trainerHover" > Classic </button> <button class="button" @click="startGame(0)" @mouseover="trainerHover('master')" @mouseout="trainerHover" > Master </button> </section> </transition> <transition name="animate-section"> <section v-if="isPlaying" class="poke-section" > <h1 class="poke-title"> Who's that pokemon? </h1> <div class="poke-question-wrapper"> <span class="poke-question"> <span class="poke-question-number"> {{ question }} </span> <span class="poke-question-amount"> / {{ questionAmount}} </span> </span> <span class="poke-score"> {{ score }} <small>pts</small> </span> <div class="poke-image" :class="{'poke-image-success': isChecked && selected.name === answer.name, 'poke-image-error': isChecked && selected.name !== answer.name}" > <img :src="image" alt="No cheating" class="poke-image-img" > </div> <transition-group tag="div" name="animate-options" :class="{'poke-options-answers': isChecked}" class="poke-options" > <button v-for="(pokemon, index) in options" :key="pokemon.name" :data-index="index" :class="{'selected': selected.index === index, 'success': isChecked && pokemon.name === answer.name , 'error': isChecked && selected.index === index && selected.name !== answer.name}" class="poke-options-button" @click="selectAnswer(pokemon.name, index)" >{{ pokemon.name | prettifyName }}</button> </transition-group> <footer class="poke-buttons"> <button :disabled="isChecked || Object.keys(selected).length < 1" class="button" @click="checkAnswer" >Submit</button> <button :disabled="!isChecked" class="button" @click="getNextQuestion" >Next</button> </footer> </div> </section> </transition> <transition name="animate-section"> <section v-if="isDone" class="poke-final" > <h2>Final score</h2> <span class="poke-final-score"> <span class="poke-final-score-number">{{ score }}</span> pts </span> <button class="button" @click="restartGame" >Play again</button> </section> </transition> </> </div>
CSS(SCSS):
@import 'https://fonts.googleapis.com/css?family=VT323'; $black: #333; $white: #fff; $primary-color: #f65a52; $primary-color-dark: darken( $primary-color, 10% ); $primary-color-tint: lighten( $primary-color, 15% ); $primary-font: "VT323", monospace; $secondary-color: #94acbd; $secondary-color-dark: darken( $secondary-color, 10% ); $options-color: #c5d5ee; $options-color-hover: darken( $options-color, 7% ); $success-color: #7bd55a; $error-color: #ff8b62; $border-radius-main: 1rem; $border-width: 6px; $border-main: solid $border-width $black; $options-height: 48px; * { box-sizing: border-box; } body { background-color: $primary-color; font-family: $primary-font; font-size: 16px; line-height: 1.875em; color: $black; } .container { width: 100%; max-width: 400px; position: relative; margin: 50px auto; } h2 { font-size: 1.25rem; white-space: nowrap; } .spacer { margin-bottom: 0.5rem; } .button { padding: 0.5em 1.5em; border-radius: $border-radius-main; border: solid 1px transparent; font-family: $primary-font; font-size: 1.5rem; background-color: $primary-color-dark; color: $black; cursor: pointer; transition: 0.35s; &:focus { outline: none; border: 1px dotted lighten($primary-color, 8%); } &:not([disabled]) { &:hover { background-color: $black; color: $primary-color; } } } .poke-section { display: flex; flex-direction: column; align-items: center; position: relative; max-width: 500px; margin: auto; } .poke-intro-trainer { position: relative; margin-bottom: 1rem; height: 200px; width: 200px; .poke-trainer-img { position: absolute; left: 50%; bottom: 0; height: 200px; opacity: 0; transition: 0.4s cubic-bezier(.22,.75,.53,.99); @media (max-width: 479px) { display: none; } &.active { transform: translateX(-50%); opacity: 1; } &-classic { bottom: 5px; height: 180px; image-rendering: pixelated; transform: translateX(-80%); } &-master { transform: translateX(-20%); } } } .poke-ball { position: absolute; top: 50%; left: 50%; height: 150px; width: 150px; border-radius: 50%; background-color: $primary-color-dark; transform: translate(-50%, -50%); overflow: hidden; &::before, &::after { content: ''; position: absolute; } &::before { z-index: 2; top: 50%; left: 50%; height: 40px; width: 40px; border-radius: 50%; border: solid $border-width $primary-color; background-color: $primary-color-tint; transform: translate(-50%, -50%); } &::after { z-index: 1; top: 50%; height: 50%; width: 100%; border-top: solid $border-width $primary-color; background-color: $primary-color-tint; } } .poke-title { position: absolute; top: -2rem; } .poke-question { position: absolute; right: calc(100% + 0.5rem); display: flex; flex-direction: column; align-items: flex-end; &-wrapper { position: relative; width: 250px; } &-number { font-size: 8rem; line-height: 0.4; color: $primary-color-tint; } } .poke-score { position: absolute; top: 6rem; right: calc(100% + 0.5rem); padding-top: 1rem; font-size: 1.25rem; white-space: nowrap; color: $black; &::before { content: ''; position: absolute; top: 0; right: 0; width: 40px; height: $border-width; background-color: $black; } } .poke-image { position: relative; z-index: 2; display: flex; justify-content: center; align-items: center; width: 250px; height: 250px; border-radius: $border-radius-main; border: $border-main; background-color: $white; overflow: hidden; &::before, &::after { content: ''; position: absolute; z-index: -1; border-radius: 50%; } &::before { width: 100px; height: 100px; background-color: $options-color; opacity: 1; transition: 0.65s ease-in-out; } &::after { width: 100px; height: 100px; border: solid ($border-width * 2) $options-color; transform: scale(0); transition: 0.4s ease-in-out; } &-img { width: auto; height: 150px; } &-success, &-error { &::before { transform: scale(4); opacity: 0.5; } &::after { transform: scale(1); } } &-success { &::before { background-color: $success-color; } &::after { border-color: $success-color; } } &-error { &::before { background-color: $error-color; } &::after { border-color: $error-color; width: 10px; border-radius: $border-radius-main; transform: rotate(45deg); } } } .poke-options { position: relative; display: flex; flex-direction: column; align-items: center; z-index: 3; top: -30px; padding: 0 20px; margin: 0 auto; width: 170px; border-radius: $border-radius-main; background-color: $black; &:not(.poke-options-answers) { .poke-options-button { &:not(.selected) { &:hover { background-color: $options-color-hover; // color: $primary-color-dark; transform: translateY(-$border-width / 2); } &:active { &::before { transform: translate(-50%, -50%) scale(1); } } } } } &.poke-options-answers { .poke-options-button { cursor: default; &:not(.error):not(.success) { color: $secondary-color; } } } &-button { position: relative; width: 100%; padding: 0.5em; min-width: 200px; max-height: $options-height; border: $border-main; border-radius: $border-radius-main; background-color: $options-color; font-family: $primary-font; font-size: 1.125rem; transition: 0.45s; cursor: pointer; overflow: hidden; &:focus { outline: none; } &::before { content: ''; position: absolute; z-index: -1; left: 50%; top: 50%; height: 200px; width: 200px; border-radius: 50%; background-color: $secondary-color; transform: translate(-50%, -50%) scale(0); transition: 0.2s ease-in-out; } &:not(:last-child) { margin-bottom: $border-width / 2; } &.selected { background-color: $secondary-color; } &.error { background-color: $error-color; } &.success { background-color: $success-color; } } } .poke-buttons { text-align: center; @media (min-width: 480px) { position: absolute; top: 20px; left: 100%; .button { padding-left: calc(1em + 10px); border-top-left-radius: 0; border-bottom-left-radius: 0; transform: translateX(-10px); } } .button { padding: 1em; width: 110px; height: 100px; color: $white; &[disabled] { color: $primary-color-tint; opacity: 0.7; cursor: default; } &:not([disabled]) { &:hover { transform: translateX(0); } } &:not(:last-child) { margin-bottom: $border-width; } } } .poke-final { text-align: center; &-score { display: block; position: relative; margin-bottom: 1rem; &::before { content: ''; position: absolute; z-index: -1; top: 50%; left: 50%; height: 100px; width: 100px; border-radius: 50%; border: solid ($border-width * 2) $primary-color-dark; transform: translate(-50%, -50%); opacity: 0.3; animation: grow 2s infinite ease-in-out; } &-number { font-size: 8rem; line-height: 0.4; color: $primary-color-tint; } } } .poke-classic { .poke-image { &-img { image-rendering: pixelated; } } } .animate-section { &-enter-active, &-leave-active { transition: 0.4s ease-in-out; } &-enter, &-leave-to { opacity: 0; } &-enter { .poke-final-score-number { transform: translateY(-30px); } } &-leave-active { transform: translateX(-30%); } &-enter-active { transition-delay: 0.1s; position: absolute; top: 0; left: 50%; transform: translateX(-50%); } } .animate-options { &-enter-active { transition: 0.4s ease-in-out; @for $i from 4 through 8 { &:nth-child(#{$i}) { transition-delay: 0.2s * ($i - 4); } } } &-enter { transform: rotateX(-45deg); transform-origin: top center; opacity: 0; } &-leave-active { position: absolute; z-index: -1; transition: 0.8s ease-in-out; // @for $i from 0 through 3 { // $child: $i + 1; // &:nth-child(#{$child}) { // top: ($options-height + $border-width / 2) * $i; // } // } &[data-index="0"] { top: 0; } &[data-index="1"] { top: ($options-height + $border-width / 2); } &[data-index="2"] { top: ($options-height + $border-width / 2) * 2; } &[data-index="3"] { top: ($options-height + $border-width / 2) * 3; } } &-leave-to { opacity: 0; } } @keyframes grow { 0%, 100% { transform: translate(-50%, -50%) scale(1) } 50% { transform: translate(-50%, -50%) scale(0.6) } }
JAVASCRIPT:
console.clear(); const pkmnTotal = 802; const url = `https://pokeapi.co/api/v2/pokemon/?limit=${pkmnTotal}`; const optionAmount = 4; let pokemonData = []; const prettyNames = { 'nidoran-f': 'nidoran♀', 'nidoran-m': 'nidoran♂', 'mr-mime': 'mr. mime', 'deoxys-normal': 'deoxys', 'wormadam-plant': 'wormadam', 'mime-jr': 'mime jr.', 'giratina-altered': 'giratina', 'shaymin-land': 'shaymin', 'basculin-red-striped': 'basculin', 'darmanitan-standard': 'darmanitan', 'tornadus-incarnate': 'tornadus', 'thundurus-incarnate': 'thundurus', 'landorus-incarnate': 'landorus', 'keldeo-ordinary': 'keldeo', 'meloetta-aria': 'meloetta', 'meowstic-male': 'meowstic', 'aegislash-shield': 'aegislash', 'pumpkaboo-average': 'pumpkaboo', 'gourgeist-average': 'gourgeist', 'oricorio-baile': 'oricorio', 'lycanroc-midday': 'lycanroc', 'wishiwashi-solo': 'wishiwashi', 'type-null': 'type: null', 'minior-red-meteor': 'minior', 'mimikyu-disguised': 'mimikyu', 'tapu-koko': 'tapu koko', 'tapu-lele': 'tapu lele', 'tapu-bulu': 'tapu bulu', 'tapu-fini': 'tapu fini' } const app = new Vue({ el: '#app', filters: { prettifyName(name) { return prettyNames[name] || name; } }, data() { return { pokemon: [], pkmnAmount: null, score: 0, question: 0, questionAmount: 10, answer: {}, selected: {}, options: [], isPlaying: false, isDone: false, isChecked: false, trainerHovered: null } }, computed: { image() { let url = 'https://raw.githubusercontent.com/tiffachoo/pokesprites/master/pokemon/' let imageUrl = `${url}${this.classic ? 'redblue' : 'sunmoon'}/` let number = this.answer.url.match(/\/(\d+)/)[1]; return `${imageUrl}${number}.png` }, classic() { return this.pkmnAmount <= 151 } }, mounted() { let pokeList = localStorage.getItem('pokeList'); if (pokeList) { pokemonData = JSON.parse(pokeList); } else { this.getData() .then(res => { pokemonData = res.results localStorage.setItem('pokeList', JSON.stringify(res.results)); }); } }, methods: { getData() { return fetch(url) .then(res => res.json()) .catch(err => console.log('errrr')); }, startGame(val) { this.question = 0; this.score = 0; this.isPlaying = true; this.pokemon = [...pokemonData]; this.pkmnAmount = val || pkmnTotal; this.getNextQuestion(); }, getNextQuestion() { this.question += 1; this.resetAnswer(); if (this.question <= this.questionAmount) { let removed = ''; for (let i = 1; i <= optionAmount; i++) { removed = this.pokemon.splice(this.getRandomPokemon(i), 1)[0]; if (i === 1) { this.answer = removed; } else { this.options.push(removed); } } let pos = Math.floor(Math.random() * optionAmount); this.options.splice(pos, 0, this.answer); } else { this.isPlaying = false; this.isDone = true; this.resetAnswer(); } }, selectAnswer(ans, index) { if (!this.isChecked) { this.$set(this.selected, 'name', ans); this.$set(this.selected, 'index', index); } }, checkAnswer() { this.isChecked = true; if (this.selected.name === this.answer.name) { this.score += 10; } }, getRandomPokemon(index) { const diff = (this.question - 1) * 4 + index; return Math.floor(Math.random() * (this.pkmnAmount + 1 - diff)); }, resetAnswer() { this.options = []; this.selected = {}; this.answer = {}; this.isChecked = false; }, restartGame() { this.isDone = false; }, trainerHover(val) { this.trainerHovered = val; } } })
Hope you enjoyed it guys..Give your time then you can see Miracles happening...
HAPPY CODING.
No comments: