diff --git a/.eslintrc b/.eslintrc index ae31524..d05f39a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,3 +1,6 @@ { - "extends": "hrundel/browser" + "extends": "hrundel/browser", + "parserOptions": { + "sourceType": "module" + } } diff --git a/drawer.js b/drawer.js new file mode 100644 index 0000000..808b660 --- /dev/null +++ b/drawer.js @@ -0,0 +1,56 @@ +/* global mina:true*/ +import snap from 'snapsvg'; + +class Drawer { + + drawHero() { + this.layout = snap('.hero__picture'); + this.head = this.layout.circle(60, 50, 50).attr({ fill: '#cca0a0' }); + this.eyes = this.layout.group( + this.layout.circle(80, 30, 10), + this.layout.circle(40, 30, 10) + ); + this.eyes.attr({ fill: '#CF4D6F' }); + this.mouth = this.layout.path('M20,70C40,90,80,90,100,70').attr({ fill: '#C97282' }); + this.nose = this.layout.path('').attr({ fill: '#76818E' }); + this.nose = this.layout.group( + this.layout.circle(60, 50, 12).attr({ fill: '#ecc5c4' }), + this.layout.circle(54, 50, 3).attr({ fill: '#b85f69' }), + this.layout.circle(66, 50, 3).attr({ fill: '#b85f69' }), + ); + this.paws = this.layout.group( + this.layout.circle(10, 55, 10), + this.layout.circle(110, 55, 10), + this.layout.circle(40, 100, 10), + this.layout.circle(80, 100, 10) + ); + this.paws.attr({ fill: '#ecc5c4' }); + } + + animateDeath() { + this.stopSpeak(); + this.eyes.attr({ fill: '#000' }); + this.mouth.animate({ d: 'M20,80C40,60,80,60,100,80' }, 1000); + } + + animateWake() { + this.eyes.attr({ fill: 'none' }).animate({ fill: '#CF4D6F' }, 1500, mina.easeinout); + this.paws.animate({ transform: 't0, 2' }, 500, mina.easein, () => { + this.paws.animate({ transform: 't0, -2' }, 500, mina.easein); + }); + } + + stopSpeak() { + if (this.ears) { + this.ears.attr({ opacity: 0 }); + } + } + + startSpeak() { + this.ears = this.layout.group(this.layout.polygon([14, 30, 40, 4, 0, 0]), + this.layout.polygon([106, 30, 80, 4, 110, 0])); + this.ears.attr({ fill: '#b85f69' }, 10000, mina.easein); + } +} + +export default new Drawer(); diff --git a/hrunogochi.js b/hrunogochi.js new file mode 100644 index 0000000..989ddd6 --- /dev/null +++ b/hrunogochi.js @@ -0,0 +1,132 @@ +'use srtict'; + +// eslint-disable-next-line no-empty-function +const bounded = (value) => Math.max(0, Math.min(100, value)); +const tickInterval = 1750; + +const phrases = [ + 'хрю-хрю-хрю', + 'давай играть', + 'ох-ох' +]; + +export default class Hrunogochi { + constructor(state) { + this.init(state); + } + + init(state) { + this.state = state || this.getState(); + this.eating = false; + this.sleeping = false; + this.speaking = false; + } + + getState() { + return { + 'bellyful': 100, + 'energy': 100, + 'mood': 100 + }; + } + + isDead() { + const { bellyful, energy, mood } = this; + + return [bellyful, energy, mood].filter(value => value === 0).length > 1; + } + + get energy() { + return this.state.energy; + } + + set energy(value) { + this.state.energy = bounded(value); + } + + get bellyful() { + return this.state.bellyful; + } + + set bellyful(value) { + this.state.bellyful = bounded(value); + } + + get mood() { + return this.state.mood; + } + + set mood(value) { + this.state.mood = bounded(value); + } + + setState({ bellyful, energy, mood }) { + this.bellyful = bellyful; + this.energy = energy; + this.mood = mood; + + this.onUpdate(); + } + + updateState(newState) { + const mergedState = Object.assign({}, this.state, newState); + this.setState(mergedState); + } + + saveState(saveAction) { + saveAction(this.state); + } + + start() { + // eslint-disable-next-line max-statements + const tick = () => { + if (this.isDead()) { + this.onDeath(); + + return this.stop(); + } + + if (Math.random() > 0.8) { + const text = phrases[Math.floor(Math.random() * phrases.length)]; + this.onSpeak(text); + } + + let { bellyful, energy, mood } = this; + + if (this.speaking) { + mood += 4; + } else if (this.sleeping) { + energy += 4; + } else if (this.eating) { + bellyful += 4; + } + + bellyful--; + energy--; + mood--; + + this.updateState({ + bellyful, + energy, + mood + }); + + this.tickId = setTimeout(tick, tickInterval); + }; + + tick(); + this.onStart(); + } + + stop() { + clearTimeout(this.tickId); + } + + reset() { + this.onReset(); + this.stop(); + this.setState(this.getState()); + this.start(); + } + +} diff --git a/index.css b/index.css index e69de29..08b2a6f 100644 --- a/index.css +++ b/index.css @@ -0,0 +1,58 @@ +html, +body +{ + margin: 0; + padding: 0; + height: 100%; +} + +body +{ + display: flex; +} + +header +{ + text-align: center; + margin-bottom: 1em; +} + +.game +{ + width: 35%; + margin: auto; + border: 2px black solid; + padding: 2em; +} + +.state, +.controls +{ + display: flex; + justify-content: space-between; +} + +.state__item, +.controls__item +{ + text-align: center; +} + +.controls__item +{ + padding: 5px 10px; + font-size: 15px; +} + +.hero +{ + margin: 10px; + display: flex; + flex-direction: column; + align-items: center; +} + +.hero__speech +{ + margin: 10px; +} diff --git a/index.html b/index.html index ae344b1..e482c68 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,36 @@