[css + svg] パックマンのキャラアニメーション#3 敵キャラパターン作成

2023年4月15日

CSS SVG ゲーム

eyecatch 敵キャラゴーストをグレードアップしました。 色分けと、パワーボールを取った時の困ったチャン表示です。

ソースコード

ghost.html

<link rel='stylesheet' href='multi_ghost.css' /> <script src='multi_ghost.js'></script> <style>body{background-color:black}</style> <div class='ghost' data-color='1' data-status='weak'> <div class='head'></div> <div class='face'> <div class='eye-left'></div> <div class='eye-right'></div> <svg class='mouse' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 10"> <path fill='none' stroke='white' stroke-width='4' d="M 15,7 Q 15,7 17.5,3 T 25,5 35,5 45,5 55,5 65,5 75,5 85,7"> <animate attributeName='d' dur='800ms' repeatCount='indefinite' calcMode="linear" values='M 15,7 Q 15,7 17.5,3 T 25,5 35,5 45,5 55,5 65,5 75,5 85,7; M 15,3 Q 15,3 17.5,7 T 25,5 35,5 45,5 55,5 65,5 75,5 85,3; M 15,7 Q 15,7 17.5,3 T 25,5 35,5 45,5 55,5 65,5 75,5 85,7;' /> </path> </svg> </div> <div class='under'> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 30"> <path d="M 0,0 Q 0,15 5,20 T 20,15 40,15 60,15 80,15 100,15 L 100,0"> <animate attributeName='d' dur='500ms' repeatCount='indefinite' calcMode="linear" values='M 0,0 Q 0,15 5,20 T 15,15 35,15 55,15 75,15 100,15 L 100,0; M 0,0 Q 0,15 5,20 T 25,15 45,15 65,15 85,15 100,15 L 100,0; M 0,0 Q 0,15 5,20 T 15,15 35,15 55,15 75,15 100,15 L 100,0;' /> </path> </svg> </div> </div> <div class='ghost' data-color='1'> <div class='head'></div> <div class='face'> <div class='eye-left'></div> <div class='eye-right'></div> </div> <div class='under'> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 30"> <path fill='red' d="M 0,0 Q 0,15 5,20 T 20,15 40,15 60,15 80,15 100,15 L 100,0" fill='red'> <animate attributeName='d' dur='500ms' repeatCount='indefinite' calcMode="linear" values='M 0,0 Q 0,15 5,20 T 15,15 35,15 55,15 75,15 100,15 L 100,0; M 0,0 Q 0,15 5,20 T 25,15 45,15 65,15 85,15 100,15 L 100,0; M 0,0 Q 0,15 5,20 T 15,15 35,15 55,15 75,15 100,15 L 100,0;' /> </path> </svg> </div> </div> <div class='ghost' data-color='2'> <div class='head'></div> <div class='face'> <div class='eye-left'></div> <div class='eye-right'></div> </div> <div class='under'> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 30"> <path d="M 0,0 Q 0,15 5,20 T 20,15 40,15 60,15 80,15 100,15 L 100,0"> <animate attributeName='d' dur='500ms' repeatCount='indefinite' calcMode="linear" values='M 0,0 Q 0,15 5,20 T 15,15 35,15 55,15 75,15 100,15 L 100,0; M 0,0 Q 0,15 5,20 T 25,15 45,15 65,15 85,15 100,15 L 100,0; M 0,0 Q 0,15 5,20 T 15,15 35,15 55,15 75,15 100,15 L 100,0;' /> </path> </svg> </div> </div> <div class='ghost' data-color='3'> <div class='head'></div> <div class='face'> <div class='eye-left'></div> <div class='eye-right'></div> </div> <div class='under'> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 30"> <path d="M 0,0 Q 0,15 5,20 T 20,15 40,15 60,15 80,15 100,15 L 100,0"> <animate attributeName='d' dur='500ms' repeatCount='indefinite' calcMode="linear" values='M 0,0 Q 0,15 5,20 T 15,15 35,15 55,15 75,15 100,15 L 100,0; M 0,0 Q 0,15 5,20 T 25,15 45,15 65,15 85,15 100,15 L 100,0; M 0,0 Q 0,15 5,20 T 15,15 35,15 55,15 75,15 100,15 L 100,0;' /> </path> </svg> </div> </div> <div class='ghost' data-color='4'> <div class='head'></div> <div class='face'> <div class='eye-left'></div> <div class='eye-right'></div> </div> <div class='under'> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 30"> <path d="M 0,0 Q 0,15 5,20 T 20,15 40,15 60,15 80,15 100,15 L 100,0"> <animate attributeName='d' dur='500ms' repeatCount='indefinite' calcMode="linear" values='M 0,0 Q 0,15 5,20 T 15,15 35,15 55,15 75,15 100,15 L 100,0; M 0,0 Q 0,15 5,20 T 25,15 45,15 65,15 85,15 100,15 L 100,0; M 0,0 Q 0,15 5,20 T 15,15 35,15 55,15 75,15 100,15 L 100,0;' /> </path> </svg> </div> </div>

multi_ghost.css

.ghost{ --size-chara : 80px; --size-width : calc(var(--size-chara) * 1.0); --size-eye : calc(var(--size-width) * 0.3); --size-under : calc(var(--size-width) * 0.2); --color-body : red; margin:50px; width:var(--size-chara); height:var(--size-chara); } .ghost[data-color='1']{--color-body : red;} .ghost[data-color='2']{--color-body : orange;} .ghost[data-color='3']{--color-body : lightblue;} .ghost[data-color='4']{--color-body : pink;} .ghost[data-status='weak']{--color-body : blue;} .ghost > *{ margin : 0 auto; width : var(--size-width); } .ghost > .head{ height : calc(var(--size-width) / 2); background-color : var(--color-body); border-radius : var(--size-chara) var(--size-chara) 0 0; } .ghost > .face{ height : 30%; background-color : var(--color-body); position:relative; } .ghost > .face > .eye-left, .ghost > .face > .eye-right{ position:absolute; top:-15px; background-color:white; width : var(--size-eye); height : var(--size-eye); background-color:white; border-radius:50%; } .ghost > .face .eye-left{ left:13%; } .ghost > .face .eye-right{ right:13%; } .ghost:not([data-status='weak']) > .face > *::before{ content:''; display:block; background-color:black; width : 50%; height : 50%; margin : 25%; border-radius:50%; transition-property : margin; transition-duration : 0.3s; } .ghost:not([data-status='weak']) > .face[data-direction='right'] > *::before{ margin-left : 50%; margin-right : 0; } .ghost:not([data-status='weak']) > .face[data-direction='left'] > *::before{ margin-left : 0; margin-right : 50%; } .ghost:not([data-status='weak']) > .face[data-direction='top'] > *::before{ margin-top : 0; margin-bottom : 50%; } .ghost:not([data-status='weak']) > .face[data-direction='bottom'] > *::before{ margin-top : 50%; margin-bottom : 0; } .ghost[data-status='weak'] > .face > .eye-left, .ghost[data-status='weak'] > .face > .eye-right{ width : calc(var(--size-eye) / 2); height : calc(var(--size-eye) / 2); background-color:white; border-radius:50%; } .ghost[data-status='weak'] > .face > .eye-left{ left:25%; } .ghost[data-status='weak'] > .face > .eye-right{ right:25%; } .ghost[data-status='weak'] > .face > .mouse{ margin-top:10px; } .ghost > .under{ height : var(--size-under); } .ghost > .under path{ fill:var(--color-body); }

multi_ghost.js

function change_eye(){ this.directions = ['right','left','top','bottom'] this.direction = this.directions[0] this.change() } change_eye.prototype.change = function(){ const elms = document.querySelectorAll('.ghost .eye') for(const elm of elms){ const num = Math.floor(Math.random() * this.directions.length) elm.setAttribute('data-direction' , this.directions[num]) } setTimeout(this.change.bind(this) , 2000) } switch(document.readyState){ case 'complete': case 'interactice': new change_eye() break default: window.addEventListener('load' , (()=>{ new change_eye() })) }

デモ

解説

javascriptもcssも前回の設定から若干変更を加えています。 色分けするため、svgに直接付けていた色(赤色)をcssでタイプ別にセット出来るようにしています。 javascriptも、複数の敵キャラが同時に目がキョロキョロするように対応しました。 パワーボールじを食べた時の敵キャラ(青色)は、口を加えていますが、これらはすべて同じhtml構造にするので、今回のcssには記載してませんが、本番ではdata-status='week'の状態以外では非表示になるようにします。 口の波アニメが体の裾部分と同じくあまり気に入った動きをしていないんですが、このへんはこだわって時間を掛けるよりも、今回は進行優先で進めたいと思います。 キャラタイプによって、アニメーションのタイミングなどを切り替えると、もっと動きにフラクラル感が出ていいかもしれませんね。 作り終わるとこうした気づきもあるので、一旦作って自己評価するというのも重要という事がよく分かります。

知財

パックマンは、バンダイナムコ社の登録商標です。 PAC-MAN™ & ©1980 BANDAI NAMCO Entertainment Inc.

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。