From eef880e05240b23b9428b3b962aa3c3e3a9f23b6 Mon Sep 17 00:00:00 2001 From: ntr Date: Tue, 23 Jul 2019 16:01:07 +1000 Subject: [PATCH 1/6] attak --- client/animations.test.js | 2 +- client/src/animations.socket.jsx | 13 ++-- client/src/animations.test.jsx | 74 ++++++++++----------- client/src/components/animations.jsx | 3 +- client/src/components/anims/attack.jsx | 90 ++++++++++---------------- 5 files changed, 80 insertions(+), 102 deletions(-) diff --git a/client/animations.test.js b/client/animations.test.js index 11f0a948..96a91b4e 100644 --- a/client/animations.test.js +++ b/client/animations.test.js @@ -1,6 +1,6 @@ require('./assets/styles/styles.css'); require('./assets/styles/styles.mobile.css'); -require('./assets/styles/instance.css'); +require('./assets/styles/instance.less'); require('./assets/styles/instance.mobile.css'); require('./assets/styles/game.css'); diff --git a/client/src/animations.socket.jsx b/client/src/animations.socket.jsx index fb0666b4..ce2e883e 100644 --- a/client/src/animations.socket.jsx +++ b/client/src/animations.socket.jsx @@ -28,12 +28,9 @@ function createSocket(store) { if (animating) return false; store.dispatch(actions.setAnimating(true)); - return eachSeries(newRes, (r, cb) => { if (['Disable', 'TargetKo'].includes(r.event[0])) return cb(); - store.dispatch(actions.setResolution(r)); - // convert server enum into anims keywords // todo make serersideonly const sequence = animations.getSequence(r); @@ -41,13 +38,15 @@ function createSocket(store) { const anims = animations.getObjects(r, sequence, game, account); const text = animations.getText(r, sequence); + store.dispatch(actions.setAnimFocus(animations.getFocusTargets(r))); + if (sequence.includes('START_SKILL')) store.dispatch(actions.setAnimSource(anims.animSource)); if (sequence.includes('END_SKILL')) store.dispatch(actions.setAnimTarget(anims.animTarget)); if (sequence.includes('POST_SKILL')) { // timeout to prevent text classes from being added too soon setTimeout( () => store.dispatch(actions.setAnimText(text)), - timeout - 1000, + timeout - TIMES.POST_SKILL_DURATION_MS ); } @@ -55,9 +54,11 @@ function createSocket(store) { store.dispatch(actions.setAnimSource(null)); store.dispatch(actions.setAnimTarget(null)); store.dispatch(actions.setAnimText(null)); - return setTimeout(cb, 50); + store.dispatch(actions.setAnimFocus([])); + // We currently need another small timeout so that everything can properly dismount / unload + // Otherwise 3 x Attack on same target will only render the first time + return setTimeout(cb, 200); }, timeout); - }, err => { if (err) return console.error(err); // clear animation state diff --git a/client/src/animations.test.jsx b/client/src/animations.test.jsx index 3704c4f6..2127ab35 100644 --- a/client/src/animations.test.jsx +++ b/client/src/animations.test.jsx @@ -69,48 +69,48 @@ document.fonts.load('16pt "Jura"').then(() => { }); const SKILLS = [ - 'AbsorbI', - 'AbsorptionI', - 'AmplifyI', + 'Absorb', + 'Absorption', + 'Amplify', 'Attack', - 'BanishI', - 'BashI', - 'BlastI', + 'Banish', + 'Bash', + 'Blast', 'Block', - 'BreakI', + 'Break', 'Buff', - 'ChaosI', - 'CounterAttackI', - 'CounterI', - 'CurseI', + 'Chaos', + 'CounterAttack', + 'Counter', + 'Curse', 'Debuff', - 'DecayI', - 'DecayTickI', - 'ElectrifyI', - 'ElectrocuteI', - 'ElectrocuteTickI', - 'HasteI', + 'Decay', + 'DecayTick', + 'Electrify', + 'Electrocute', + 'ElectrocuteTick', + 'Haste', 'HasteStrike', - 'HealI', + 'Heal', 'HybridBlast', - 'HybridI', - 'InterceptI', - 'InvertI', - 'LinkI', - 'PurgeI', - 'PurifyI', - 'RechargeI', - 'ReflectI', - 'RestrictI', - 'RuinI', - 'SilenceI', - 'SiphonI', - 'SiphonTickI', - 'SlayI', - 'SleepI', - 'StrikeI', + 'Hybrid', + 'Intercept', + 'Invert', + 'Link', + 'Purge', + 'Purify', + 'Recharge', + 'Reflect', + 'Restrict', + 'Ruin', + 'Silence', + 'Siphon', + 'SiphonTick', + 'Slay', + 'Sleep', + 'Strike', 'Stun', - 'SustainI', - 'TriageI', - 'TriageTickI', + 'Sustain', + 'Triage', + 'TriageTick', ]; diff --git a/client/src/components/animations.jsx b/client/src/components/animations.jsx index 1a4e3ee6..5e0cd1c9 100644 --- a/client/src/components/animations.jsx +++ b/client/src/components/animations.jsx @@ -3,6 +3,7 @@ const { Component } = require('preact'); const { connect } = require('preact-redux'); const Amplify = require('./anims/amplify'); +const Attack = require('./anims/attack'); const Absorb = require('./anims/absorb'); const Bash = require('./anims/bash'); const Blast = require('./anims/blast'); @@ -69,7 +70,7 @@ class ConstructAnimation extends Component { const chooseAnim = (skill) => { switch (skill) { // Attack base - case 'Attack': return ; + case 'Attack': return ; case 'Blast': return ; case 'Siphon': return ; case 'SiphonTick': return ; diff --git a/client/src/components/anims/attack.jsx b/client/src/components/anims/attack.jsx index e851a7f2..f49798ac 100644 --- a/client/src/components/anims/attack.jsx +++ b/client/src/components/anims/attack.jsx @@ -2,81 +2,57 @@ const preact = require('preact'); const { Component } = require('preact'); const anime = require('animejs').default; -const dagger = require('../svgs/dagger'); -const { TIMES } = require('../../constants'); - -const duration = TIMES.TARGET_DURATION_MS; +const { TIMES, COLOURS } = require('../../constants'); class Attack extends Component { constructor(props) { super(); this.props = props; + this.animations = []; } render() { return ( - {dagger(10, 250, 40, 150)} - {dagger(50, 250, 40, 150)} - {dagger(90, 250, 40, 150)} - {dagger(130, 250, 40, 150)} - {dagger(170, 250, 40, 150)} - {dagger(210, 250, 40, 150)} - {dagger(250, 250, 40, 150)} + viewBox="0 0 400 400"> + + + + + ); } componentDidMount() { - let y = 0; - const daggers = document.querySelectorAll('.attack-anim .dagger'); - anime.set(daggers, { - y: 250, - }); - y = -150; - if (!this.props.team) { - anime.set('.attack-anim', { - rotate: 180, - }); - } else { - anime.set('.attack-anim', { - rotate: 0, - }); - } - - // if (this.props.stage === 'END_SKILL') { - // anime.set(daggers, { - // y: 400, - // }); - // y = -150; - // if (!this.props.team) { - // anime.set('.attack-anim', { - // rotate: 0, - // }); - // } else { - // anime.set('.attack-anim', { - // rotate: 180, - // }); - // } - // } - - anime({ - targets: daggers, - delay: anime.stagger(250, { - start: 250, - grid: [1, 7], - from: 'center', - easing: 'linear', - }), - y, - duration, - }); + this.animations.push(anime({ + targets: ['#attack rect'], + easing: 'easeOutExpo', + y: [400, 200], + height: [100, 10, 0], + width: [12, 5, 0], + delay: () => anime.random(TIMES.TARGET_DELAY_MS, TIMES.TARGET_DELAY_MS + TIMES.TARGET_DURATION_MS / 2), + duration: TIMES.TARGET_DURATION_MS, + })); } + + // this is necessary because + // skipping / timing / unmounting race conditions + // can cause the animations to cut short, this will ensure the values are reset + // because preact will recycle all these components + componentWillUnmount() { + for (let i = this.animations.length - 1; i >= 0; i--) { + this.animations[i].reset(); + } + } + } module.exports = Attack; From 341f4dda0948f2305754b9ec1477213e43865d22 Mon Sep 17 00:00:00 2001 From: ntr Date: Tue, 23 Jul 2019 16:40:40 +1000 Subject: [PATCH 2/6] blast and text colours --- client/assets/styles/game.css | 33 +++----- client/package.json | 2 +- client/src/components/anims/blast.jsx | 106 ++++++++++---------------- 3 files changed, 51 insertions(+), 90 deletions(-) diff --git a/client/assets/styles/game.css b/client/assets/styles/game.css index d6ccd3d8..7fc39187 100644 --- a/client/assets/styles/game.css +++ b/client/assets/styles/game.css @@ -234,65 +234,54 @@ */} .game-construct.red-damage { -/* filter: drop-shadow(0 0 0.2em red); -*/ color: red; + color: #a52a2a; /*ensure construct doesn't get opacity lowered because of being KO before the KO animation*/ opacity: 1; - - /*border-color: red;*/ } .red-damage button { - /*border: 1px solid red;*/ - color: red; + color: #a52a2a; } .red-damage text { - fill: red; + fill: #a52a2a; } .red-damage .stats { - /*border-top: 1px solid red;*/ + /*border-top: 1px solid #a52a2a;*/ } .game-construct.blue-damage { -/* filter: drop-shadow(0 0 0.2em blue); -*/ color: blue; + color: #3498db; opacity: 1; - /*border-color: blue;*/ } .blue-damage button { - /*border: 1px solid blue;*/ - color: blue; + color: #3498db; } .blue-damage text { - fill: blue; + fill: #3498db; } .blue-damage .stats { - /*border-top: 1px solid blue;*/ } .game-construct.green-damage { -/* filter: drop-shadow(0 0 0.2em green); -*/ color: green; + color: #1FF01F; opacity: 1; - /*border-color: green;*/ } .green-damage button { - /*border: 1px solid green;*/ - color: green; + color: #1FF01F; } .green-damage text { - fill: green; + fill: #1FF01F; } .green-damage .stats { - /*border-top: 1px solid green;*/ + /*border-top: 1px solid #1FF01F;*/ } .game-construct.purple-damage { diff --git a/client/package.json b/client/package.json index fbf72b65..7fcacae2 100644 --- a/client/package.json +++ b/client/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "start": "parcel watch index.html --out-dir /var/lib/mnml/public/current", - "anims": "parcel watch animations.html --out-dir /var/lib/mnml/public/current", + "anims": "parcel watch animations.html --no-hmr --out-dir /var/lib/mnml/public/current", "build": "parcel build index.html", "scss": "node-sass --watch assets/scss -o assets/styles", "lint": "eslint --fix --ext .jsx src/", diff --git a/client/src/components/anims/blast.jsx b/client/src/components/anims/blast.jsx index 9c4fcb4f..f8c66715 100644 --- a/client/src/components/anims/blast.jsx +++ b/client/src/components/anims/blast.jsx @@ -1,100 +1,72 @@ const preact = require('preact'); const { Component } = require('preact'); const anime = require('animejs').default; +const times = require('lodash/times'); -const { TIMES } = require('../../constants'); -const { randomPoints } = require('../../utils'); +const { TIMES, COLOURS } = require('../../constants'); -const duration = TIMES.TARGET_DURATION_MS; - - -function projectile(x, y, radius, colour) { - return ( - - ); -} - -class AttackCharge extends Component { - constructor(props) { +class Blast extends Component { + constructor() { super(); - this.team = props.team; this.animations = []; - const points = randomPoints(8, 60, { x: 0, y: 0, width: 300, height: 400 }); - this.charges = points.map(coord => projectile(coord[0], coord[1], 20, '#00aabb')); } render() { return ( - // {this.charges} + viewBox="0 0 300 300"> - - - - + + + + + + + - - - - - - - {this.charges} + + {times(50, () => ( + + + + + ))} + ); } componentDidMount() { - anime.set('#blast', { - translateX: -200 * this.props.direction.x, - translateY: -300 * this.props.direction.y, - }); - this.animations.push(anime({ - targets: '#blast', + targets: ['#blast'], opacity: [ - { value: 1, delay: TIMES.TARGET_DELAY_MS, duration: TIMES.TARGET_DURATION_MS * 0.3 }, - { value: 0, delay: TIMES.TARGET_DURATION_MS * 0.7, duration: TIMES.POST_SKILL_DURATION_MS }, + { value: 1, delay: TIMES.TARGET_DELAY_MS, duration: TIMES.TARGET_DURATION_MS * 0.2 }, + { value: 0, delay: TIMES.TARGET_DURATION_MS * 0.5, duration: TIMES.TARGET_DURATION_MS * 0.2 }, ], + easing: 'easeInOutSine', })); - anime.set('#explosion feDisplacementMap', { - scale: 1, - }); - this.animations.push(anime({ - targets: '#blast', - translateY: 0, - translateX: 0, - loop: false, + targets: ['#blast g'], + transform: () => ` + translate(${anime.random(-100, 100)} ${anime.random(-100, 100)}) + `, + style: { rotate: anime.random(-180, 180) }, + easing: 'easeOutCubic', delay: TIMES.TARGET_DELAY_MS, - duration: (duration * 1 / 2), - easing: 'easeInQuad', - })); - - this.animations.push(anime({ - targets: '#explosion feDisplacementMap', - scale: 200, - loop: false, - delay: TIMES.TARGET_DELAY_MS + duration * 1 / 2, - duration: duration * 1 / 2, - easing: 'easeInQuad', + duration: TIMES.TARGET_DURATION_MS, })); } + // this is necessary because + // skipping / timing / unmounting race conditions + // can cause the animations to cut short, this will ensure the values are reset + // because preact will recycle all these components componentWillUnmount() { for (let i = this.animations.length - 1; i >= 0; i--) { this.animations[i].reset(); @@ -102,4 +74,4 @@ class AttackCharge extends Component { } } -module.exports = AttackCharge; +module.exports = Blast; From 5baffffd69138ae772cef69aae640456fa9f3edd Mon Sep 17 00:00:00 2001 From: ntr Date: Tue, 23 Jul 2019 17:01:43 +1000 Subject: [PATCH 3/6] icon stuff --- client/assets/styles/instance.less | 114 ++++++++++-------- client/assets/styles/vbox.less | 9 ++ client/src/animations.socket.jsx | 12 +- client/src/components/instance.constructs.jsx | 2 +- client/src/components/shapes.jsx | 13 +- client/src/components/svgs/diamond.jsx | 6 +- client/src/utils.jsx | 2 +- 7 files changed, 91 insertions(+), 67 deletions(-) diff --git a/client/assets/styles/instance.less b/client/assets/styles/instance.less index 4b7cd9de..04077c41 100644 --- a/client/assets/styles/instance.less +++ b/client/assets/styles/instance.less @@ -287,66 +287,80 @@ flex: 1 0 100%; } +// .equipping { +// position: relative; +// } + +// .equipping::before { +// content: ''; +// position: absolute; +// top: 2px; +// left: 50%; +// width: 100%; +// height: 2px; +// transform-origin: center; +// background-color: whitesmoke; +// animation: equipping-skill 2s infinite ease-out alternate; +// opacity: 0; +// } + +// .equipping::after { +// content: ''; +// position: absolute; +// bottom: 2px; +// left: 50%; +// width: 100%; +// height: 2px; +// transform-origin: center; +// background-color: whitesmoke; +// animation: equipping-skill 2s infinite ease-out alternate; +// opacity: 0; +// animation-delay: 0.75s +// } + +// @keyframes equipping-skill { +// from { +// transform: translate(-50%, 0) scaleX(0); +// } + +// to { +// transform: translate(-50%, 0) scaleX(0.75); +// opacity: 1; +// } +// } + +// .equip-spec { +// position: relative; +// stroke: #333; +// } + +// .equip-spec::after { +// content: ''; +// position: absolute; +// bottom: 2px; +// left: 50%; +// width: 100%; +// height: 2px; +// transform-origin: center; +// background-color: whitesmoke; +// animation: equipping-skill 2s infinite ease-out alternate; +// opacity: 0; +// } + .equipping { - position: relative; + animation: equipping 2s infinite ease-in-out alternate; } -.equipping::before { - content: ''; - position: absolute; - top: 2px; - left: 50%; - width: 100%; - height: 2px; - transform-origin: center; - background-color: whitesmoke; - animation: equipping-skill 2s infinite ease-out alternate; - opacity: 0; -} - -.equipping::after { - content: ''; - position: absolute; - bottom: 2px; - left: 50%; - width: 100%; - height: 2px; - transform-origin: center; - background-color: whitesmoke; - animation: equipping-skill 2s infinite ease-out alternate; - opacity: 0; - animation-delay: 0.75s -} - -@keyframes equipping-skill { +@keyframes equipping { from { - transform: translate(-50%, 0) scaleX(0); + border-color: #444; } to { - transform: translate(-50%, 0) scaleX(0.75); - opacity: 1; + border-color: whitesmoke; } } -.equip-spec { - position: relative; - stroke: #333; -} - -.equip-spec::after { - content: ''; - position: absolute; - bottom: 2px; - left: 50%; - width: 100%; - height: 2px; - transform-origin: center; - background-color: whitesmoke; - animation: equipping-skill 2s infinite ease-out alternate; - opacity: 0; -} - .thresholds { display: flex; flex-flow: column; diff --git a/client/assets/styles/vbox.less b/client/assets/styles/vbox.less index f1947ce3..4af09140 100644 --- a/client/assets/styles/vbox.less +++ b/client/assets/styles/vbox.less @@ -78,9 +78,18 @@ background: @white; border: 1px solid @white; + // overwrite the classes on white svg elements ellipse.white { stroke: black; } + + rect.white { + stroke: black; + } + + polygon.white { + stroke: black; + } } } diff --git a/client/src/animations.socket.jsx b/client/src/animations.socket.jsx index ce2e883e..c1567fa5 100644 --- a/client/src/animations.socket.jsx +++ b/client/src/animations.socket.jsx @@ -41,7 +41,10 @@ function createSocket(store) { store.dispatch(actions.setAnimFocus(animations.getFocusTargets(r))); if (sequence.includes('START_SKILL')) store.dispatch(actions.setAnimSource(anims.animSource)); - if (sequence.includes('END_SKILL')) store.dispatch(actions.setAnimTarget(anims.animTarget)); + if (sequence.includes('END_SKILL')) { + store.dispatch(actions.setAnimTarget(anims.animTarget)); + if (!['Banish', 'Invert'].includes(anims.animTarget.skill)) store.dispatch(actions.setAnimCb(cb)); + } if (sequence.includes('POST_SKILL')) { // timeout to prevent text classes from being added too soon setTimeout( @@ -49,15 +52,14 @@ function createSocket(store) { timeout - TIMES.POST_SKILL_DURATION_MS ); } - return setTimeout(() => { store.dispatch(actions.setAnimSource(null)); store.dispatch(actions.setAnimTarget(null)); store.dispatch(actions.setAnimText(null)); store.dispatch(actions.setAnimFocus([])); - // We currently need another small timeout so that everything can properly dismount / unload - // Otherwise 3 x Attack on same target will only render the first time - return setTimeout(cb, 200); + if (!sequence.includes('END_SKILL') + || ['Banish', 'Invert'].includes(anims.animTarget.skill)) return cb(); + return true; }, timeout); }, err => { if (err) return console.error(err); diff --git a/client/src/components/instance.constructs.jsx b/client/src/components/instance.constructs.jsx index bda246d2..5a027298 100644 --- a/client/src/components/instance.constructs.jsx +++ b/client/src/components/instance.constructs.jsx @@ -144,7 +144,7 @@ function Construct(props) { if (!s) { const equipping = specList.includes(vbox.bound[itemEquip]); - const classes = `${equipping ? 'equip-spec' : 'gray'} empty`; + const classes = `${equipping ? 'equipping' : 'gray'} empty`; return (