Forked from: Tomo's GYAOS_sample diff(2018) forked from: GYAOS_sample Tenderfeel Follow 2011-01-31 22:22:10 License: MIT License Fork1 Fav4 View3543 マウスジェスチャーでモンスターに行動指示を出します アイテムは数が減るだけです。 時間帯で背景が変化します。 Play Stop Reload Fullscreen Smart Phone Fork tree Readme JavaScript 1465 lines HTML 6 lines CSS 536 lines マウスジェスチャーでモンスターに行動指示を出します アイテムは数が減るだけです。 時間帯で背景が変化します。 forked from: GYAOS_sample google.load("mootools", "1.3.0",{uncompressed:true}); google.setOnLoadCallback( function() { (function($) { //マウスジェスチャー var MoouseGesture = new Class({ Implements:[Options,Events], options:{ canvasSize:{x:465, y:465}, lineColor : {r:255, g:0, b:0, a:1}, command:{},//code:callback onComplete:null }, initialize: function(elm, options) { this.setOptions(options); this.element = $(elm); this.element.width = this.options.canvasSize.x; this.element.height = this.options.canvasSize.y; this.color = this.options.lineColor; this.keepCommand = {}; this.commands = this.options.command; this.gesture = { 'active':false, 'startPos': {x:0, y:0}, 'lastPos':{x:0, y:0}, 'curPos': {x:0, y:0}, 'code':'' }; window.addEvents({ 'mousedown': function(e) { var cfix = this.element.getPosition(); this.gesture.active = true; this.gesture.startPos = this.gesture.lastPos = this.gesture.curPos = {x:e.client.x - cfix.x, y:e.client.y - cfix.y}; this.fireEvent('start'); }.bind(this), 'mousemove': function(e) { this.draw(e); }.bind(this), 'mouseup': function(e) { this.gesture.active = false; if(this.gesture.code) { if(this.keepCommand[this.gesture.code]) { this.keepCommand[this.gesture.code](e); this.keepCommand = {}; } else if(typeof this.commands[this.gesture.code] == 'function') { this.commands[this.gesture.code](e); } else if(typeof this.commands[this.gesture.code] == 'object') { this.keepCommand = this.commands[this.gesture.code]; } } this.gesture.code = ''; this.clear.delay(500, this); }.bind(this) }); }, getCode : function() { return this.gesture.code; }, setColor: function(color) { this.color = color; return this; }, addGesture: function(code, callback) { this.commands[code] = callback; return this; }, addGestures: function(obj) { this.commands = obj; return this; }, appendGestures :function(obj){ this.commands = Object.append(this.commands, obj); return this; }, getGestures:function(){ return this.commands; }, removeGesture: function(code) { this.commands = Object.filter(this.commands, function(value, key) { return key != code; }); return this; }, clearGesture: function() { this.commands = {}; return this; }, clear : function() { this.element.getContext('2d').clearRect(0,0,this.element.width, this.element.height); this.keepCommand = {}; this.fireEvent('complete'); }, draw : function(e) { if(! this.gesture.active) return; var cfix = this.element.getPosition(); var nextPos = {x:e.client.x - cfix.x, y:e.client.y - cfix.y}; var prevPos = this.gesture.lastPos; this.gesture.lastPos = nextPos; var ctx = this.element.getContext('2d'); ctx.strokeStyle = 'rgba('+this.color.r+','+this.color.g+','+this.color.b+','+this.color.a+')'; ctx.lineWidth = '1'; ctx.lineCap = 'butt'; ctx.beginPath(); ctx.moveTo(prevPos.x, prevPos.y); ctx.lineTo(nextPos.x, nextPos.y); ctx.stroke(); this.getAngle(nextPos); }, getAngle: function(nextPos) { var diff = {x:nextPos.x- this.gesture.curPos.x, y:nextPos.y- this.gesture.curPos.y}; var log = (this.gesture.code !== '') ? this.gesture.code.substr(-1,1) : ''; var ncode = null; if(Math.abs(diff.x) > 3 * Math.abs(diff.y)) {//水平 if(diff.x > 0) {//水平右 ncode = 6; } else {//水平左 ncode = 4; } } else if(Math.abs(diff.y) > 3 * Math.abs(diff.x)) {//垂直 if(diff.y > 0) {//垂直下 ncode = 2; } else {//垂直上 ncode = 8; } } else if(diff.y < 0) {//上斜め if(diff.x < 0) {//左上 ncode = 7; } else {//右上 ncode = 9; } } else {//下斜め if(diff.x < 0) {//左下 ncode = 1; } else {//右下 ncode = 3; } } if(ncode == log) { this.gesture.curPos = nextPos; } else if((Math.abs(diff.x) > 30 || Math.abs(diff.y) > 30)) { this.gesture.code += ncode; this.gesture.curPos = nextPos; } } }); /*---------------------------------------------------- * ダイアログ ----------------------------------------------------*/ var Dialog = new Class({ Extends: Fx.CSS, options:{ defaultStyle:{'background':'rgba(0,0,0,0.5)'}, duration:300, link:'cancel' }, initialize: function(element, options) { this.element = this.subject = document.id(element); this.property = 'opacity'; this.delayTimer = 0; this.parent(element, options); }, start: function(from, to) { if (!this.check('opacity', from, to)){ return this; } var args = Array.flatten(arguments); var parsed = this.prepare(this.element, this.property, args); return this.parent(parsed.from, parsed.to); }, set: function(now) { this.render(this.element, this.property, now, this.options.unit); return this; }, stop : function() { this.stopTimer(); if(this.delayTimer){ clearTimeout(this.delayTimer); } this.clearChain(); this.element.setStyles(this.options.defaultStyle); return this; }, setMessage: function(txt) { this.element.set('html', txt); return this; }, showInOut: function(txt) { this.stop(); this.delayTimer = this.setMessage(txt).show().fadeOut.delay(1000,this); return this; }, show: function(txt) { this.stop(); if(txt){ this.setMessage(txt); } return this.set(1); }, hide: function() { this.stop(); return this.set(0); }, fadeOut: function() { return this.stop().start(0); }, highlight: function(text, colors) { var $this = this; var fnc = []; if(text){ this.setMessage(text); } colors.each( function(col) { fnc.push( function() { $this.element.setStyle('background-color', col); this.callChain.delay(100, this); }); }); fnc.push( function() { this.delayTimer = this.callChain.delay(900, this); }); fnc.push( function() { $this.fadeOut(); return this; }); this._chain(fnc); return this; }, _chain: function(fnc) { this.set(1); this.chain.apply(this, fnc); this.callChain(); } }); /*---------------------------------------------------- * コンソール ----------------------------------------------------*/ var Console = new Class({ Extends:Fx.Morph, options:{ windowTarget:$('container'), buttonTarget:$('container'), set:[ { 'content':'Hello World', 'button':'Console', 'open':{'bottom':35,'opacity':1}, 'styles':{'background':'rgba(255,255,255,0.1)','height':120} } ], show:false, duration:300, link:'cancel' }, setWindow: function(num, obj) { this.options.set[num] = obj; return this; }, destroy: function() { this.element.destroy(); return this; }, reset: function() { this.initialize(); return this; }, initialize: function(options) { var element = new Element('div', {'id':'console'}); this.parent(element, options); this.element.inject(this.options.windowTarget); var height = this.element.getSize().y; this.set({'bottom':-height,'opacity':0}); this.active = false; this.next = 0; this.reopen = false; this.setInner(); if(this.options.show!==false) { this.open(this.options.show); } }, onComplete: function() { if(this.reopen) { this.reopen=false; this.open(this.next); return; } if(this.active!==false) { this.fireEvent('open',[this.element, this.inner[this.active], this.active]); } else { this.fireEvent('close',[this.element, this.inner]); } }, setInner: function() { var $this = this; this.inner = []; var length = Object.getLength(this.options.set); var buttonWrap = new Element('div',{'id':'console-controller'}); Array.each(this.options.set, function(set,i) { var inner = new Element('div', {'class':'inner'}); if(set.content && typeof set.content == 'object') { set.content.inject(inner); } else { inner.set('html', set.content); } $this.inner[i] = inner; var button = new Element('a', {'href':'#', 'class':'consoleButton ' + set.className, 'html':'<span>'+set.button+'</span>'}); button.store('num',i); button.addEvent('click', function(e) { e.stop(); $this.toggle( this.retrieve('num')); }); button.inject(buttonWrap); }); buttonWrap.inject(this.options.buttonTarget); return this; }, toggle: function(num, reopen) { if(this.active !==num || reopen) { this.next = num; this.reopen=true; } if(this.active!==false) { this.close(); } else { this.open(num); } return this; }, close: function() { var height = this.element.getSize().y; this.start({'bottom':-height,'opacity':0}); this.element.toggleClass('open'); this.element.empty(); if(!this.reopen){ this.active = false; } return this; }, open: function(num) { num = (num)? num : 0; var set = this.options.set[num]; this.active = num; this.inner[num].inject(this.element); if(typeof set.styles == 'object') { this.element.setStyles(set.styles); } this.start(set.open).chain( function() { this.element.addClass('open'); }.bind(this)); return this; } }); /*---------------------------------------------------- * モンスター ----------------------------------------------------*/ var Monster = new Class({ Extends:Fx.Morph, options: { 'name':'Monster', 'exp':0,//経験値 'type':'',//種族 'img':'', 'maxhp':100,//MAX体力 'status':{ 'lv':1, 'HP':100,//体力 'STR':5,//力 'VIT':5,//持久力 'DEX':5,//器用 'AGI':5,//敏捷 'INT':5,//かしこさ 'MND':5,//精神 'CHR':5 //魅力 }, 'condition':{//状態 'concent':0, //集中 'napping':0, //隙 'guard':0, //ガード 'confu':0, //混乱 'dark':0, //暗闇 'silent':0, //沈黙 'excite':0, //興奮 'sleep':0, //睡眠 'poison':0, //毒 'parayz':0 //麻痺 }, 'link':'cancel', 'pet':false, //プレイヤーが所有してたらtrue 'duration':200, 'transition':'back:inOut' }, initialize: function(options) { this.setOptions(options); var element = new Element('img', {'id':'monster','src':this.options.img}); this.parent(element, options); this.status = this.options.status; this.hp = this.options.status.HP; this.move = false; this.counter = 0; //出現後の経過時間カウント this.timer = null; //内部モーションタイマー }, getName: function() { return this.options.name; }, getLevel: function() { return this.options.status.lv; }, getImage: function() { return this.element; }, getType: function() { return this.options.type; }, getOption: function(key) { return this.options[key]; }, getHp : function() { return this.hp; }, setHp: function(hp) { this.hp = hp; return this; }, getCondition:function(key){ if(key){ return this.options.condition[key]; }else{ return this.options.condition; } }, setCondition:function(key,val){ if(val!==''){ this.options.condition[key] =val; }else{ this.options.condition = key; } }, getStatus: function(key) { if(key){ return this.status[key]; }else{ return this.status; } } }); var Motion = { //攻撃 slash:function(){ var $this = this; var effect = this.element.getPrevious('.effect'); if(effect){ effect.destroy(); } var div = new Element('div', {'class':'effect', 'styles':{'height':465, 'width':465,'opacity':0, 'position':'absolute','top':0,'left':0,'z-index':2}}); var divFx = new Fx.Morph(div, {duration:100,onComplete:function(){this.element.destroy();}}); div.inject(this.element, 'before'); var styles = this.element.getStyles('width','top','left'); this.setOptions({'transition':'cubic:Out','duration':200}); this.start({'width':360, 'top':-70, 'left':50}) .chain(function(){ $this.start({'top':20}); divFx.start({'background-color':'#f00', 'opacity':1}) .chain(function(){divFx.start({'opacity':0});}) .chain(function(){divFx.start({'opacity':1});}) .chain(function(){divFx.start({'opacity':0});}); }, function(){ $this.setOptions({'transition':'back:Out'}); $this.start(styles); }); }, //離れる distance:function(){ this.setOptions({ duration:300, 'transition':'quad:out' }); this.start({'left':130, 'width':200, 'top':70}); return this; }, //フェードアウト fadeOut:function(){ this.setOptions({'duration':1000,'transition':'quint:out'}); this.start({'opacity':0}).chain(function(){ this.element.destroy();}.bind(this)); return this; }, //だんだん離れて消える fadeAway:function(){ this.setOptions({'duration':2000,'transition':'quint:out'}); this.start({'left':180, 'width':100, 'top':150,'opacity':0}).chain(function(){ this.element.destroy();}.bind(this)); return this; }, //近づく approach:function(){ this.setOptions({ duration:300, 'transition':'quad:out' }); this.start({'left':110, 'width':240, 'top':50}); return this; }, //被ダメージ pain: function(damage) { this.setOptions({'duration':100,'transition':'bounce:inOut'}); var text = new Element('span', {'text':damage, 'class':'damage','morph':{'duration':1000,'transition':'cubic:out','onComplete':function(){this.element.destroy();}}}); text.inject(this.element,'before').morph({'opacity':0, 'top':160}); this.start({'left':120, 'width':220}) .chain( function() { this.start({'left':110, 'width':240}); }.bind(this) ); return this; }, //体力0 die:function(){ this.setOptions({'duration':1500,'transition':'quint:out', 'onComplete':function(){this.element.destroy();}}); this.start({'opacity':0}); } }; Monster.implement(Motion); /* サンプルのモンスター --------------------------------------------------*/ var Lion = new Class({ Extends: Monster, options:{ 'name':'フラワーライオン', 'exp':5000, 'type':'ネコ科', 'img':'http://www.cyberagent.co.jp/img/media/kayac/monster01.png', 'maxhp':400,//MAX体力 'status':{ 'lv':5, 'HP':400,//体力 'STR':10,//力 'VIT':10,//持久力 'DEX':10,//器用 'AGI':10,//敏捷 'INT':10,//かしこさ 'MND':10,//精神 'CHR':10 //魅力 } }, initialize: function(options) { this.parent(options); } }); /*---------------------------------------------------- * プレイヤー ----------------------------------------------------*/ var Player = new Class({ Implements: [Options], options: { 'name': 'Player', 'exp':0, 'maxhp':100, 'status':{ 'lv':1, 'HP':100,//体力 'VIT':5, 'STR':5,//力 'DEX':5,//器用 'AGI':5,//敏捷 'INT':5,//かしこさ 'MND':5,//精神 'CHR':5 //魅力 }, 'pets':[], 'items':[] }, initialize: function(options) { this.setOptions(options); this.pets = this.options.pets; this.petIndex = 0; this.activePet = this.pets[this.petIndex];//戦闘中のペット }, getName: function() { return this.options.name; }, getLv: function() { return this.options.status.lv; }, getStatus: function() { return this.options.status; }, getHp: function() { return this.status.hp; }, getItems: function() { return this.options.items; }, setItem: function(i, num) { this.options.items[i].num = num; }, getPets: function() { return this.pets; }, getActive: function() { return this.activePet; }, setPetIndex: function(num) { this.petIndex = num; }, setActive: function(i) { this.activePet = this.pets[i]; }, pet: function() { return this.getActive(); } }); var Versus = new Class({ setVersus: function(pet, npc) { this.pet = pet; this.npc = npc; }, versusGuard:function(how){ switch(how){ case 1: this.npc.distance(); this.npc.setCondition('guard', 1); this.ui.message.showInOut(this.npc.getName()+ ' はガードの構え'); break; default: this.npc.approach(); this.npc.setCondition('guard', 0); this.ui.message.showInOut(this.npc.getName()+ ' はガードを解いた'); break; } }, versusAttack:function(to){ var $this = this; var s = (to=='npc') ? 'pet':'npc'; var mName = (to=='npc') ? this.pet.getName():this.npc.getName(); var tName = (to=='npc') ? this.npc.getName():this.pet.getName(); this.versusAnim = new Chain(); this.versusAnim.chain( function(){ $this[s].move = true; if(to=='npc'){ $this.addLog('attack start', mName + ' に攻撃を指示'); $this.ui.message.showInOut(mName + ' に攻撃を指示'); } this.callChain.delay(1000, this); }, function(){ $this.ui.message.show(mName + ' の攻撃!'); $this.addLog('attack', mName + ' は ' + tName + ' に攻撃した'); this.callChain.delay(1000, this); }, function(){ var result = $this.decide(s, to, $this[s].getStatus()); if(to == 'npc'){ $this.setScope(); }else{ $this.setStatus(); } if(result.dmg > 0){ $this.addLog('attack', tName + 'に'+result.dmg+'のダメージ'); $this.ui.message.highlight( tName + 'に'+result.dmg+'のダメージ', ['rgba(255, 0, 0, 0.7)','rgba(0, 0, 0, 0.5)','rgba(255, 0, 0, 0.7)','rgba(0, 0, 0, 0.5)']); }else{ $this.addLog('attack miss', tName + ' は攻撃を回避した'); $this.ui.message.showInOut( tName + ' は攻撃を回避!'); } var d = 3000 - $this[s].getStatus('AGI')*80; this.callChain.delay(d, this); }, function(){ if($this[to].getHp() > 0){ $this[s].move = false; }else{ $this.versusAnim.clearChain(); if(to == 'npc'){ $this.defeat(); }else{ $this.gameOver(); } return; } } ); this.versusAnim.callChain(); }, decide:function(s, to, status){ var dmg = this.calcAtk(status) - this.calcDfn(status.VIT, this[s].getLevel(), this[to].getCondition('guard')); var hit = this.calcHit(s, to); if(hit === 0) { return {'dmg':0, 'hp':this[to].getHp()}; }else if(hit <=10){ dmg = Math.floor(dmg/2 - Math.random()); } var point = this[to].getHp() - dmg; if(point<=0){ point = 0; } this[to].setHp(point); if(to=='npc'){ this[to].pain(dmg); }else{ this[s].slash(); } return {'dmg':dmg, 'hp':point}; }, //攻撃力 calcAtk:function(status){ return Math.floor((((status.STR * 0.7) + (status.DEX * 0.3)) - Math.random()) * status.lv); }, //防御 calcDfn:function(vit, lv, guard){ var d = Math.floor(vit/2 + lv + (guard * 20 - Math.random())); return d; }, //命中率 calcHit:function(s,to){ var m = Math.floor(Math.sqrt(this[s].getStatus('DEX')) - this[to].getStatus('AGI')*2)+100; var h = Math.floor(Math.random() * m); return h; } }); /*---------------------------------------------------- * アクション ----------------------------------------------------*/ var Action = new Class({ //逃げる escape: function(success) { var $this = this; this.showModeTip('battle','Escape Mode'); this.ui.message.show('逃走方向を指示してください <strong class="confirm"><span class="yes">×</span> でキャンセル</strong>'); this.gesture.clearGesture(); this.console.close(); var successEsc = function(){ clearTimeout($this.monster.timer); clearTimeout($this.player.pet().timer); $this.versusAnim.clearChain(); $this.monster.fadeAway(); $this.layer.scope.fade(0); $this.ui.message.show($this.monster.getName()+'の前から逃げ出した'); $this.addLog('escape success', $this.monster.getName()+'の前から逃げ出した'); }; var escapeMiss = function(){ $this.addLog('escape miss', $this.player.getName()+' は 逃走に失敗'); $this.ui.message.showInOut(' 逃げられない!'); $this.versusAnim.clearChain(); $this.versusAttack('pet'); }; var n = [2,4,6,7,8,9]; var cmd = { 1:{ 3:this.battle.bind(this) }, 3:{ 1:this.battle.bind(this) }, 2:escapeMiss, 4:escapeMiss, 6:successEsc, 7:escapeMiss, 8:escapeMiss, 9:successEsc }; this.gesture.addGestures(cmd); }, //アイテム使用 useItem: function() { this.showModeTip('battle','Inventory'); this.console.toggle(3, true); }, //モンスター変更 changeMonster: function() { this.showModeTip('battle','Change Monster'); this.console.toggle(2, true); }, //つかまえる(モンスター衰弱時・隙がtrueの時にコマンド発生) capture : function() { this.showModeTip('battle','Capture Mode'); }, /** * たたかう */ battle: function() { var $this = this; var timer = 0; var petName = this.player.pet().getName(); var monsName = this.monster.getName(); var checkActive = function(){ if(!$this.player.pet().move && $this.player.pet().getCondition('guard')===0){ $this.ui.status.name.className = 'name star'; }else{ $this.ui.status.name.removeClass('star'); } }; this.player.pet().timer = checkActive.periodical(500); this.ui.message.hide(); this.player.pet().setCondition('guard',0); if(this.player.pet().getCondition('guard')===0) { this.monster.approach(); } //ログメッセージ this.addLog('battle start', petName + ' は '+monsName+' と 戦闘を開始'); this.showModeTip('battle','Battle Mode'); this.console.setWindow(0, { 'content':null, 'button':'Command', 'open':{'bottom':40,'opacity':1}, 'styles':{ 'height':120, 'background':'url(http://demo.webtecnote.com/nyaos/images/cmd-battle.png) no-repeat center bottom', 'border':0 } }); this.console.toggle(0, true); //通常攻撃 var attack = function() { $this.showModeTip('battle','Battle Mode'); if( $this.player.pet().getCondition('guard')) { $this.addLog('battle error', 'ガード中は攻撃できない'); $this.ui.message.showInOut( 'ガード中は攻撃できない'); return; }else if($this.player.pet().move || $this.monster.move){ return; } $this.versusAttack('npc'); }; //特殊攻撃 var skill = function() { $this.showModeTip('battle','Battle Mode'); $this.addLog('skill start', petName + ' に 百烈拳を指示'); $this.ui.message.showInOut(petName + ' に 百烈拳を指示'); }; //ガード? var guard = function() { $this.showModeTip('battle','Battle Mode'); $this.addLog('guard start', petName + ' に ガードを指示'); $this.ui.message.showInOut(petName + ' に ガードを指示'); $this.player.pet().setCondition('guard', 1); $this.monster.distance(); }; var escapeMiss = function(){ $this.showModeTip('battle','Battle Mode'); $this.addLog('escape miss', $this.player.getName()+' は 逃走に失敗'); $this.ui.message.showInOut(' 逃げられない!'); }; //前進 var advance = function(){ if( $this.player.pet().getCondition('guard')) { $this.addLog('guard off', petName + ' に ガード解除を指示'); $this.ui.message.showInOut(petName + ' に ガード解除を指示'); $this.monster.approach(); $this.player.pet().setCondition('guard', 0); } }; //バトル中コマンド var cmd = { 6:attack, 1:{ 3:skill }, 3:{ 1:skill }, 8:advance, 2:guard, 89632:this.escape.bind(this, true), 8963:this.escape.bind(this, true), 8932:escapeMiss, 8631:escapeMiss, 9632:escapeMiss, 963:escapeMiss, 932:escapeMiss, 632:escapeMiss, 698:this.useItem.bind(this) }; //ジェスチャーセット this.gesture.addEvent('complete', function(){ if(this.console.active==1){ this.updateLog(this.console.element, this.console.inner[1]); } }.bind(this)); this.gesture.addGestures(cmd); } }); /*---------------------------------------------------- * メイン ----------------------------------------------------*/ var Gyaos = this.Gyaos = new Class({ Implements: [Chain, Events, Options, Action,Versus], options: { layer : { 'container':$('container'), 'main':$('main'), 'canvas':$('canvas') } }, initialize: function(options) { this.subject = this.subject || this; this.setOptions(options); this.gamelog = [];//ログ this.layer = this.options.layer;//レイヤー this.versus = null;//クラス var message = new Element('div',{'id':'message'}); message.fade('hide').inject(this.layer.container,'top'); this.ui = { 'message':new Dialog(message), 'status':{}, 'scope':{} }; //モンスデータ this.monsterData = [ new Lion() ]; //プレイヤー this.player = new Player({ 'name': 'ああああ', 'exp':10000, 'status':{ 'lv':10, 'HP':500,//体力 'STR':25,//力 'VIT':25, 'DEX':25,//器用 'AGI':25,//敏捷 'INT':25,//かしこさ 'MND':25,//精神 'CHR':25 //魅力 }, 'items':[ {'name':'薬草', 'num':5}, {'name':'万能薬', 'num':3}, {'name':'落とし穴', 'num':1} ], 'pets':[ new Lion({ 'name':'ライオン丸', 'exp':10000, 'maxhp':400, 'img':'http://www.cyberagent.co.jp/img/media/kayac/monster01.png', 'status':{ 'lv':5, 'HP':400,//体力 'STR':14,//力 'VIT':8,//持久力 'DEX':8,//器用 'AGI':12,//敏捷 'INT':8,//かしこさ 'MND':5,//精神 'CHR':10 //魅力 }, 'condition':{//状態 'guard':1 //ガード }, 'pet':true }) ] }); this.gesture = new MoouseGesture(this.layer.canvas); this.console = new Console({ set:[ { 'className':'command', 'content':null, 'title':'マウスジェスチャーコマンド', 'button':'Command', 'open':{'bottom':38,'opacity':1}, 'styles':{ 'background':'url(http://demo.webtecnote.com/nyaos/images/cmd-1.png) no-repeat center top', 'height':120, 'border':0 } }, { 'className':'log', 'title':'ログ', 'content':this.getLogHTML(), 'button':'Log', 'open':{'bottom':38,'opacity':1}, 'styles':{'background':'rgba(255,255,255,0.3)','height':100,'border':'solid 1px rgba(255,255,255,0.45)','border-bottom':'solid 1px #000'} }, { 'className':'monster', 'title':'モンスター変更', 'content':this.monsterList(), 'button':'Monster', 'open':{'bottom':38,'opacity':1}, 'styles':{'background':'rgba(255,255,255,0.2)','height':100,'border':'solid 1px rgba(255,255,255,0.35)','border-bottom':'solid 1px #000'} }, { 'className':'item', 'title':'アイテム', 'content':this.setInventory(), 'button':'Item', 'open':{'bottom':38,'opacity':1}, 'styles':{'background':'rgba(255,255,255,0.2)','height':100,'border':'solid 1px rgba(255,255,255,0.35)','border-bottom':'solid 1px #000'} } ], show:0, onClose: function(el, inner) { }.bind(this), onOpen: function(el, inner, num) { switch(num) { case 1: this.updateLog(el, inner); break; case 2: inner.empty(); this.monsterList().inject(inner); new Element('div', {'id':'petList-nav', 'html':'<span class="current">●</span><span>○</span><span>○</span>'}).inject(inner); break; default: break; } }.bind(this) }); this.createLayer(); this.encount(); }, //レイヤー作成 createLayer: function() { //モードチップ var mode = new Element('div',{'id':'mode'}); mode.inject(this.layer.container); this.layer['mode'] = mode; //ステータス var status = new Element('div',{'id':'status'}); status.inject(this.layer.container); this.layer['status'] = status; this.createStatusElement(); }, //敵ステ createScope:function(){ var scope = new Element('div', {'id':'scope'}); var name = new Element('div', {'class':'name', 'text':this.monster.getName()}); var hp = new Element('span', {'class':'hp'}); var count = new Element('span',{'class':'count'}); var bar = new Element('span', {'class':'bar'}); this.layer['scope'] = scope; this.ui.scope['name'] = name; this.ui.scope['hp'] = hp; this.ui.scope['count'] = count; this.ui.scope['bar'] =bar; scope.fade('hide').inject(this.layer.main); name.inject(scope); bar.inject(hp); count.inject(hp); hp.inject(scope); this.ui.scope['barx'] = this.ui.scope.bar.getSize().x; return this; }, setScope:function(){ var pet = this.monster; var barvars = this.getHpCoordinates(this.ui.scope.barx, pet); this.ui.scope.count.set('text',pet.getHp()); //this.ui.scope.level.set('text', 'Lv' +pet.getLevel()); this.ui.scope.hp.addClass(barvars.className); this.ui.scope.bar.setStyle('width', barvars.width); this.ui.scope.bar.set('title', 'Max:'+pet.getStatus('HP')+'('+barvars.par+'%)'); return this; }, //ステータスの中身作成 createStatusElement: function() { var wrap = new Element('div', {'id':'info'}); var hp = new Element('div',{'class':'hp'}); var lv = new Element('span', {'class':'level'}); var count = new Element('span',{'class':'count'}); var bar = new Element('span', {'class':'bar'}); var name = new Element('div',{'class':'name', 'html':'<strong>'+this.player.pet().getName()+'</strong>'}); this.ui.status['hp'] = hp; this.ui.status['level'] = lv; this.ui.status['count'] = count; this.ui.status['bar'] =bar; this.ui.status['name'] =name; name.inject(wrap); lv.inject(name,'top'); bar.inject(hp); count.inject(hp); hp.inject(wrap); wrap.inject(this.layer.status); this.ui.status['barx'] = bar.getSize().x; return this; }, //HPの割合とか getHpCoordinates: function(x, pet) { var par = (pet.getHp()/pet.getStatus('HP')).toFloat(1); var w = x * par; var className = 'good'; if(par <= 0.25) { className = 'danger'; } else if(par <= 0.50) { className = 'attention'; } return {'x': x, 'par': (par*100), 'width':w, 'className': className}; }, /** * ステータスのセッター * * HP class : good -> attention -> danger */ setStatus : function() { var pet = this.player.pet(); var barvars = this.getHpCoordinates(this.ui.status.barx, pet); this.ui.status.count.set('text',pet.getHp()); this.ui.status.level.set('text', 'Lv' +pet.getLevel()); this.ui.status.hp.addClass(barvars.className); this.ui.status.bar.setStyle('width', barvars.width); this.ui.status.bar.set('title', 'Max:'+pet.getStatus('HP')+'('+barvars.par+'%)'); }, //デフォルトのジェスチャーコマンド setDefaultGesture: function() { var command = { 8:this.battle.bind(this), 2:this.escape.bind(this), 6:this.changeMonster.bind(this), 4:this.useItem.bind(this) }; this.gesture.addGestures(command); }, /** * #container 背景色のセット * 20 - 5 : Night * 6 - 10 : Morning * 11 - 16 : Daytime * 17 - 19 : Evening */ setBackground: function() { var time = new Date().getHours(); if(time >= 0 && time <= 5) { this.layer.container.addClass('night'); } else if(time >=6 && time <= 10) { this.layer.container.addClass('morning'); } else if(time >= 11 && time <= 16) { this.layer.container.addClass('daytime'); } else if(time >= 17 && time <= 19) { this.layer.container.addClass('evening'); } else { this.layer.container.addClass('night'); } }, //ログの追加 addLog: function(key, text) { this.gamelog.push([new Date().getTime(), key, text]); }, /** * ログ生成 */ getLogHTML : function() { var log = new Element('ul', {'class': 'log'}); this.gamelog.each( function(item, i) { var date = new Date(); date.setTime(item[0]); new Element('li', {'text':item[2], 'class': item[1]}).inject(log); }); return log; }, updateLog:function(parent, inner){ inner.empty(); var mt = parent.retrieve('mt'); var log = this.getLogHTML(); log.set({ 'tween':{ 'duration':300, 'property':'margin-top', onComplete:function(e){ parent.store('mt', e.getStyle('margin-top').toInt()); }.bind(this)} }); log.setStyle('margin-top', mt).inject(inner); var h = log.getSize().y - inner.getSize().y; if(h > 0){ log.tween(-h); } }, /** * モードチップ */ showModeTip: function(className, text) { this.layer.mode.set('html','<small class="mode '+className+'">'+text+'</small><strong>'+this.player.getName()+'</strong>'); this.layer.mode.addClass(className); this.layer.mode.fade(1); }, //アイテム袋 setInventory: function() { var $this = this; var items = new Element('div.itemList'); this.player.getItems().each( function(item,i) { var li = new Element('a',{'href':'#','html': '<span class="name">' + item.name + '</span><span class="num">'+ item.num+'</span>'}); li.addEvent('click', function() { var i = this.retrieve('i'); var n = this.retrieve('stock'); if(n===0) return; n--; $this.player.setItem(i, n); this.store('stock', n); this.getElement('.num').set('text', n); }); li.store('i', i); li.store('stock', item.num); li.inject(items); }); return items; }, //モンスターリスト monsterList: function() { var $this = this; var table = new Element('table',{'class':'petList'}); var cmd = this.gesture.getGestures(); this.player.getPets().each( function(pet, i) { var tr = new Element('tr'); var th = new Element('th',{'class':'name', 'html':'<strong>'+pet.getName()+'</strong><span class="level">Lv'+pet.getLevel()+'</span><span class="type">'+pet.getType()+'</span>'}); th.setStyle('background-image', 'url('+pet.getOption('img')+')'); th.inject(tr); var petStatus = pet.getStatus(); var status = ''; Object.each(petStatus, function(val, key) { if(key == 'HP') return; status += '<small>' + key + '</small><em>' + val+'</em>'; }); var bar = new Element('span', {'class':'bar'}); var barvars = $this.getHpCoordinates(240, pet); var hp = new Element('div',{'class':'hp '+barvars.className, 'title': 'Max:'+pet.getStatus('HP')+'('+barvars.par+'%)'}); var count = new Element('span',{'class':'count', 'text':pet.getHp()}); bar.setStyle('width',barvars.width).inject(hp); count.inject(hp); var td = new Element('td',{'class':'info', 'html':'<div class="status">'+status+'</div>'}); hp.inject(td, 'top'); td.inject(tr); tr.inject(table); var change = function(i) { //this.player.setActive(i); $this.ui.message.showInOut('変更しました '); $this.gesture.addGestures(cmd); $this.console.toggle(0); }; var cancel = function(i) { $this.ui.message.hide(); $this.gesture.addGestures(cmd); $this.console.toggle(0); }; tr.addEvent('click', function(e) { var table = this.getParent('table'); dispose = table.getChildren().dispose(); e.target.getParent('tr').addClass('selected').inject(table); var confirm = new Element('div',{'class':'confirm'}); $this.ui.message.show('このモンスターに変更しますか? <strong class="confirm"><span class="yes"">YES ↑</span> <span class="no">NO ↓</span></strong> '); var command = { 8:change.bind(i), 2:cancel.bind(i) }; $this.gesture.addGestures(command); }); }); return table; }, //エンカウント encount : function() { this.monster = this.monsterData.getRandom(); this.setStatus(); this.createScope(); this.layer.scope.fade(1); this.setScope(); this.showModeTip('battle','Mode Choice'); this.monster.getImage().inject(this.layer.main); this.setBackground(); this.addLog('encount', this.monster.getName()+' が現れた!'); //コマンドセット this.setDefaultGesture(); this.ui.message.showInOut(this.monster.getName()+' が現れた!'); this.setVersus(this.player.pet(), this.monster); //アニメーション開始 this.monster.start({'opacity':[0,1],'top':[-50,70]}); this.moveNpc(); }, moveNpc:function(){ var $this = this; this.monster.timer = 0; var normal = function(){ if($this.player.pet().getHp() > 0 && (!$this.player.pet().move && !$this.monster.move)){ $this.versusAttack('pet'); }else{ return; } }; $this.monster.timer = normal.periodical(2000); }, defeat:function(){ clearTimeout(this.monster.timer); clearTimeout(this.player.pet().timer); if(this.monster.hp <= 0){ this.monster.die(); this.layer.scope.fade(0); this.ui.message.showInOut(this.monster.getName()+' を倒した'); this.addLog('defeat', this.player.pet().getName() +' は ' + this.monster.getName()+' を倒した'); this.setDefaultGesture(); } }, gameOver:function(from){ clearTimeout(this.monster.timer); clearTimeout(this.player.pet().timer); this.ui.message.showInOut(this.player.pet().getName()+' は力尽きた…'); this.addLog('defeat', this.player.pet().getName() +' は ' + this.monster.getName()+' に倒された'); this.setDefaultGesture(); this.monster.fadeOut(); this.layer.scope.fade(0); } }); new Gyaos(); })(document.id); }); <div id="container"> <div id="main"></div> <canvas id="canvas"></canvas> </div> <script type="text/javascript" src="https://www.google.com/jsapi"></script> forked from: GYAOS_sample body { font-size:13px; margin:0; padding:0; } ul { padding:0; margin:0; } li { list-style:none outside; } em { font-style:normal; } a{ text-decoration:none; color:#fff; overflow:hidden; outline:none; } #canvas { position:absolute; top:0; left:0; width:465px; height:465px; z-index:4; } #container{ position:relative; width:465px; height:465px; margin:0 auto; background-color:#000; overflow:hidden; -moz-user-select: none; -khtml-user-select: none; -webkit-user-select: none; user-select: none; } .night{ background: -moz-linear-gradient(top, #160072 0%, #07114F 46%, #000000 48%, #000528 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#160072), color-stop(46%,#07114F), color-stop(48%,#000000), color-stop(100%,#000528)); } .morning{ background: -moz-linear-gradient(top, #3989DD 0%, #0D2299 46%, #0D1242 48%, #002766 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#3989DD), color-stop(46%,#0D2299), color-stop(48%,#0D1242), color-stop(100%,#002766)); } .daytime{ background: -moz-linear-gradient(top, #5EC9FF 0%, #D1ECFF 46%, #417A34 48%, #578C47 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#5EC9FF), color-stop(46%,#D1ECFF), color-stop(48%,#417A34), color-stop(100%,#578C47)); } .evening{ background: -moz-linear-gradient(top, #160072 0%, #BA1310 46%, #000000 48%, #3F0B00 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#160072), color-stop(46%,#BA1310), color-stop(48%,#000000), color-stop(100%,#3F0B00)); } /* メッセージダイアログ ---------------------------------------------*/ #message { width:380px; background:rgba(0,0,0,0.5); color:#fff; padding:10px; position:absolute; top:10px; left:50%; margin-left:-200px; -webkit-border-radius:8px; -moz-border-radius:8px; border-radius:8px; z-index:2; } /* メイン ------------------------------------------------------- */ #main { width:100%; height:100%; font-size:12px; } #main img#monster { position:absolute; width:200px; opacity:0; left:130px; z-index:1; height:auto; } #scope { background: -moz-linear-gradient(top, #4c4c4c 0%, #595959 4%, #666666 12%, #474747 27%, #2c2c2c 44%, #000000 45%, #111111 71%, #2b2b2b 90%, #1c1c1c 96%, #131313 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#4c4c4c), color-stop(4%,#595959), color-stop(12%,#666666), color-stop(27%,#474747), color-stop(44%,#2c2c2c), color-stop(45%,#000000), color-stop(71%,#111111), color-stop(90%,#2b2b2b), color-stop(96%,#1c1c1c), color-stop(100%,#131313)); border:1px solid rgba(0,0,0,0.6); position:absolute; right:30px; top:60px; width:150px; -moz-border-radius:4px; border-radius:4px; } #scope .name { font-size:85%; color:#fff; margin:5px 5px 2px 5px; } #scope .hp { display:block; margin:0 5px 5px 5px; line-height:1; height:10px; background:url(http://demo.webtecnote.com/nyaos/images/bg_bar.png) no-repeat left bottom; -webkit-background-size:100px; -moz-background-size:100px; -o-background-size:100px; background-size:100px; overflow:hidden; } #scope .bar{ width:100px; } #main .damage{ font-size:30px; color:#ff0000; font-weight:bold; font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; position:absolute; top:180px; left:270px; z-index:2; } /*プレイヤー名とモード表示 -------------------------------------------------*/ #mode { position:absolute; border:solid 1px #101010; color:#fff; bottom:2px; left:2px; color:#efefef; width:105px; height:33px; text-align:center; background: -moz-linear-gradient(top, #24252E 0%, #000000 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#24252E), color-stop(100%,#000000)); z-index:7; } #mode strong { font-weight:normal; display:inline-block; margin-top:10px; } #mode .mode { display:block; position:absolute; top:-18px; left:0; line-height:15px; padding:0 5px; color:#6f6f6f; background:#070709; border:solid 1px #3D3D3D; font-size:9px; font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; -moz-border-radius:4px 4px 0 0; border-radius:4px 4px 0 0; } /* ステータス ------------------------------------------------------ */ #status { position:absolute; left:0; bottom:0; background:#24262f; border-top:solid 1px #3d3d3d; color:#fff; height:37px; width:355px; padding-left:115px; z-index:6; } /* 使役中のモンスター情報 */ #info { width:210px; overflow:hidden; } #info .name { margin:3px 0; } #info .name.star strong:after { content:' Ready!'; font-size:85%; color:#FFFF00; display:inline; font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; font-weight:normal; } .level { display:inline-block; padding:0 3px; margin-right:5px; font-size:85%; -moz-border-radius: 3px; border-radius: 3px; /* background: -moz-linear-gradient(top, #F8D04A 0%, #ED9017 70%, #ED7717 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#F8D04A), color-stop(70%,#ED9017), color-stop(100%,#ED7717)); text-shadow: 0px 0px 1px #b35e13; */ background: -moz-linear-gradient(top, #cedce7 0%, #596a72 100%); /* firefox */ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#cedce7), color-stop(100%,#596a72)); /* webkit */ text-shadow: 0px 0px 1px rgba(0,0,0,1); font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; } #info .hp , .petList .hp{ line-height:1; height:10px; background:url(http://demo.webtecnote.com/nyaos/images/bg_bar.png) no-repeat left bottom; -webkit-background-size:180px; -moz-background-size:180px; -o-background-size:180px; background-size:180px; } #info .hp .bar { height:8px; width:180px; display:inline-block; } .hp .count { display:inline-block; font-size:77%; line-height:1; font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; height:10px; vertical-align:top; float:right; } .good .count { color:#0D94D6; } .attention .count { color:#F8D800; } .danger .count {color:#EA0000} .good .bar { border:solid 1px #066999; background: -moz-linear-gradient(top, #0894D6 0%, #0D94D6 20%, #057DC2 20%, #0988CC 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#0894D6), color-stop(20%,#0D94D6), color-stop(20%,#057DC2), color-stop(100%,#0988CC)); -webkit-box-shadow: inset -1px -1px 1px rgba(0,180,255,1); -moz-box-shadow: inset -1px -1px 1px rgba(0,180,255,1); box-shadow: inset -1px -1px 1px rgba(0,180,255,1); } .attention .bar { border:solid 1px #c29b00; background: -moz-linear-gradient(top, #FCFAC0 0%, #FCE94D 20%, #F8D800 20%, #FFDE00 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#FCFAC0), color-stop(20%,#FCE94D), color-stop(20%,#F8D800), color-stop(100%,#FFDE00)); -webkit-box-shadow: inset -1px -1px 1px rgba(255,240,0,1); -moz-box-shadow: inset -1px -1px 1px rgba(255,240,0,1); box-shadow: inset -1px -1px 1px rgba(255,240,0,1); } .danger .bar { border:solid 1px #870404; background: -moz-linear-gradient(top, #F03B3B 0%, #F11B1C 20%, #EA0000 20%, #C80000 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#F03B3B), color-stop(20%,#F11B1C), color-stop(20%,#EA0000), color-stop(100%,#C80000)); -webkit-box-shadow: inset -1px -1px 1px #e80101; -moz-box-shadow: inset -1px -1px 1px #e80101; box-shadow: inset -1px -1px 1px #e80101; } /* コンソール ---------------------------------------------------- */ #console{ position:absolute; width:100%; bottom:10px; left:0; height:150px; overflow:hidden; background-repeat:no-repeat; background-position:center bottom; z-index:5; } #console .inner { position:relative; overflow:hidden; margin:10px; height:80px; } /* コンソールのボタン ---------------------------------------------------- */ #console-controller { position:absolute; right:3px; bottom:3px; z-index:7; height:31px; } #console-controller:active{ z-index:10 } .consoleButton { display:inline-block; color:rgba(255,255,255,0.5); margin-left:3px; cursor:pointer; height:31px; width:31px; background-repeat:no-repeat; background-position:left top; } .consoleButton span{ visibility:hidden; } .consoleButton:focus, .consoleButton:hover { background-position:left -31px !important; } .consoleButton.command{ background:url(http://demo.webtecnote.com/nyaos/images/command.png); } .consoleButton.log{ background:url(http://demo.webtecnote.com/nyaos/images/log.png); } .consoleButton.monster{ background:url(http://demo.webtecnote.com/nyaos/images/monster.png); } .consoleButton.item{ background:url(http://demo.webtecnote.com/nyaos/images/item.png); } /* .consoleButton { line-height:24px; height:24px; padding:0 0.6em; margin-left:3px; font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; font-size:85%; cursor:pointer; -webkit-border-radius:5px; -moz-border-radius:5px; border-radius:5px; background: -moz-linear-gradient(top, rgba(255,255,255,0.1) 0%, rgba(0,0,0, 0.3) 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,0.1)), color-stop(100%,rgba(0,0,0, 0.3))); } .consoleButton:hover { background: -moz-linear-gradient(top, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0.1) 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,0.3)), color-stop(100%,rgba(255,255,255,0.1))); } */ /* ログ ----------------------------------------------------- */ .log { color:#efefef; } .log li { font-size:93%; padding: 0 0 5px 0; } .log .encount { color: #EF0E0E } /* アイテムリスト ------------------------------------------------------- */ .itemList { color:#efefef; } .itemList a { margin:0 2px 5px 2px; display:inline-block; overflow:hidden; } .itemList .name { display:inline-block; background-color:rgba(62,111,87, 1); padding:2px 5px; -webkit-border-radius:3px 0 0 3px; -moz-border-radius:3px 0 0 3px; border-radius:3px 0 0 3px; } .itemList .num { display:inline-block; background-color:rgba(20,20,20,0.8); padding:2px 5px; -webkit-border-radius:0 3px 3px 0; -moz-border-radius:0 3px 3px 0; border-radius:0 3px 3px 0; } .itemList a:focus .name, .itemList a:hover .name{ background-color:rgba(102,151,127, 1); } .itemList a:focus .num, .itemList a:hover .num{ background-color:rgba(60,60,60,0.8); } /* ペットリスト -------------------------------------------------*/ .petList { color:#fff; width:100%; border-collapse:collapse; cursor:pointer; } .petList .name { background-repeat:no-repeat; background-position:-15px -30px ; -webkit-background-size: 80px auto ; -moz-background-size: 80px auto ; -o-background-size: 80px auto ; background-size: 80px auto ; height:50px; padding:0 10px 0 60px; background-color:rgba(0,0,0,0.5); -webkit-border-radius:5px 0 0 5px; -moz-border-radius:5px 0 0 5px; border-radius:5px 0 0 5px; font-weight:normal; width:35%; text-align:left; } .petList .name strong { display:block; margin-bottom:5px; } .petList .type{ font-size:77%; color:#9F9F9F; } .petList .info { padding:5px 10px; background-color:rgba(0,0,0,0.2); -webkit-border-radius: 0 5px 5px 0; -moz-border-radius: 0 5px 5px 0; border-radius: 0 5px 5px 0; font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; } /* HPのバー 一部ペットと共通 */ .petList .hp{ line-height:1; margin-bottom:5px; height:10px; background:url(http://demo.webtecnote.com/nyaos/images/bg_bar.png) no-repeat left bottom; width:269px; -webkit-background-size:240px; -moz-background-size:240px; -o-background-size:240px; background-size:240px; } .hp .bar { height:10px; width:240px; display:inline-block; line-height:1; } .petList .info small { display:inline-block; color:#cEDCE7; font-size:77%; } .petList .info em { margin-right:8px; } .petList .info em:last-child{ margin:0; } #petList-nav { text-align:center; color:#596A72; font-size:85%; margin-top:10px; } #petList-nav span { cursor:pointer; } .confirm { display:inline-block; margin-left:2em; } .confirm .yes { color:#67FF5F } .confirm .no { color:#FF885F; } マウスジェスチャーでモンスターに行動指示を出します アイテムは数が減るだけです。 時間帯で背景が変化します。 google.load("mootools", "1.3.0",{uncompressed:true}); google.setOnLoadCallback( function() { (function($) { //マウスジェスチャー var MoouseGesture = new Class({ Implements:[Options,Events], options:{ canvasSize:{x:465, y:465}, lineColor : {r:255, g:0, b:0, a:1}, command:{},//code:callback onComplete:null }, initialize: function(elm, options) { this.setOptions(options); this.element = $(elm); this.element.width = this.options.canvasSize.x; this.element.height = this.options.canvasSize.y; this.color = this.options.lineColor; this.keepCommand = {}; this.commands = this.options.command; this.gesture = { 'active':false, 'startPos': {x:0, y:0}, 'lastPos':{x:0, y:0}, 'curPos': {x:0, y:0}, 'code':'' }; window.addEvents({ 'mousedown': function(e) { var cfix = this.element.getPosition(); this.gesture.active = true; this.gesture.startPos = this.gesture.lastPos = this.gesture.curPos = {x:e.client.x - cfix.x, y:e.client.y - cfix.y}; this.fireEvent('start'); }.bind(this), 'mousemove': function(e) { this.draw(e); }.bind(this), 'mouseup': function(e) { this.gesture.active = false; if(this.gesture.code) { if(this.keepCommand[this.gesture.code]) { this.keepCommand[this.gesture.code](e); this.keepCommand = {}; } else if(typeof this.commands[this.gesture.code] == 'function') { this.commands[this.gesture.code](e); } else if(typeof this.commands[this.gesture.code] == 'object') { this.keepCommand = this.commands[this.gesture.code]; } } this.gesture.code = ''; this.clear.delay(500, this); }.bind(this) }); }, getCode : function() { return this.gesture.code; }, setColor: function(color) { this.color = color; return this; }, addGesture: function(code, callback) { this.commands[code] = callback; return this; }, addGestures: function(obj) { this.commands = obj; return this; }, appendGestures :function(obj){ this.commands = Object.append(this.commands, obj); return this; }, getGestures:function(){ return this.commands; }, removeGesture: function(code) { this.commands = Object.filter(this.commands, function(value, key) { return key != code; }); return this; }, clearGesture: function() { this.commands = {}; return this; }, clear : function() { this.element.getContext('2d').clearRect(0,0,this.element.width, this.element.height); this.keepCommand = {}; this.fireEvent('complete'); }, draw : function(e) { if(! this.gesture.active) return; var cfix = this.element.getPosition(); var nextPos = {x:e.client.x - cfix.x, y:e.client.y - cfix.y}; var prevPos = this.gesture.lastPos; this.gesture.lastPos = nextPos; var ctx = this.element.getContext('2d'); ctx.strokeStyle = 'rgba('+this.color.r+','+this.color.g+','+this.color.b+','+this.color.a+')'; ctx.lineWidth = '1'; ctx.lineCap = 'butt'; ctx.beginPath(); ctx.moveTo(prevPos.x, prevPos.y); ctx.lineTo(nextPos.x, nextPos.y); ctx.stroke(); this.getAngle(nextPos); }, getAngle: function(nextPos) { var diff = {x:nextPos.x- this.gesture.curPos.x, y:nextPos.y- this.gesture.curPos.y}; var log = (this.gesture.code !== '') ? this.gesture.code.substr(-1,1) : ''; var ncode = null; if(Math.abs(diff.x) > 3 * Math.abs(diff.y)) {//水平 if(diff.x > 0) {//水平右 ncode = 6; } else {//水平左 ncode = 4; } } else if(Math.abs(diff.y) > 3 * Math.abs(diff.x)) {//垂直 if(diff.y > 0) {//垂直下 ncode = 2; } else {//垂直上 ncode = 8; } } else if(diff.y < 0) {//上斜め if(diff.x < 0) {//左上 ncode = 7; } else {//右上 ncode = 9; } } else {//下斜め if(diff.x < 0) {//左下 ncode = 1; } else {//右下 ncode = 3; } } if(ncode == log) { this.gesture.curPos = nextPos; } else if((Math.abs(diff.x) > 30 || Math.abs(diff.y) > 30)) { this.gesture.code += ncode; this.gesture.curPos = nextPos; } } }); /*---------------------------------------------------- * ダイアログ ----------------------------------------------------*/ var Dialog = new Class({ Extends: Fx.CSS, options:{ defaultStyle:{'background':'rgba(0,0,0,0.5)'}, duration:300, link:'cancel' }, initialize: function(element, options) { this.element = this.subject = document.id(element); this.property = 'opacity'; this.delayTimer = 0; this.parent(element, options); }, start: function(from, to) { if (!this.check('opacity', from, to)){ return this; } var args = Array.flatten(arguments); var parsed = this.prepare(this.element, this.property, args); return this.parent(parsed.from, parsed.to); }, set: function(now) { this.render(this.element, this.property, now, this.options.unit); return this; }, stop : function() { this.stopTimer(); if(this.delayTimer){ clearTimeout(this.delayTimer); } this.clearChain(); this.element.setStyles(this.options.defaultStyle); return this; }, setMessage: function(txt) { this.element.set('html', txt); return this; }, showInOut: function(txt) { this.stop(); this.delayTimer = this.setMessage(txt).show().fadeOut.delay(1000,this); return this; }, show: function(txt) { this.stop(); if(txt){ this.setMessage(txt); } return this.set(1); }, hide: function() { this.stop(); return this.set(0); }, fadeOut: function() { return this.stop().start(0); }, highlight: function(text, colors) { var $this = this; var fnc = []; if(text){ this.setMessage(text); } colors.each( function(col) { fnc.push( function() { $this.element.setStyle('background-color', col); this.callChain.delay(100, this); }); }); fnc.push( function() { this.delayTimer = this.callChain.delay(900, this); }); fnc.push( function() { $this.fadeOut(); return this; }); this._chain(fnc); return this; }, _chain: function(fnc) { this.set(1); this.chain.apply(this, fnc); this.callChain(); } }); /*---------------------------------------------------- * コンソール ----------------------------------------------------*/ var Console = new Class({ Extends:Fx.Morph, options:{ windowTarget:$('container'), buttonTarget:$('container'), set:[ { 'content':'Hello World', 'button':'Console', 'open':{'bottom':35,'opacity':1}, 'styles':{'background':'rgba(255,255,255,0.1)','height':120} } ], show:false, duration:300, link:'cancel' }, setWindow: function(num, obj) { this.options.set[num] = obj; return this; }, destroy: function() { this.element.destroy(); return this; }, reset: function() { this.initialize(); return this; }, initialize: function(options) { var element = new Element('div', {'id':'console'}); this.parent(element, options); this.element.inject(this.options.windowTarget); var height = this.element.getSize().y; this.set({'bottom':-height,'opacity':0}); this.active = false; this.next = 0; this.reopen = false; this.setInner(); if(this.options.show!==false) { this.open(this.options.show); } }, onComplete: function() { if(this.reopen) { this.reopen=false; this.open(this.next); return; } if(this.active!==false) { this.fireEvent('open',[this.element, this.inner[this.active], this.active]); } else { this.fireEvent('close',[this.element, this.inner]); } }, setInner: function() { var $this = this; this.inner = []; var length = Object.getLength(this.options.set); var buttonWrap = new Element('div',{'id':'console-controller'}); Array.each(this.options.set, function(set,i) { var inner = new Element('div', {'class':'inner'}); if(set.content && typeof set.content == 'object') { set.content.inject(inner); } else { inner.set('html', set.content); } $this.inner[i] = inner; var button = new Element('a', {'href':'#', 'class':'consoleButton ' + set.className, 'html':'<span>'+set.button+'</span>'}); button.store('num',i); button.addEvent('click', function(e) { e.stop(); $this.toggle( this.retrieve('num')); }); button.inject(buttonWrap); }); buttonWrap.inject(this.options.buttonTarget); return this; }, toggle: function(num, reopen) { if(this.active !==num || reopen) { this.next = num; this.reopen=true; } if(this.active!==false) { this.close(); } else { this.open(num); } return this; }, close: function() { var height = this.element.getSize().y; this.start({'bottom':-height,'opacity':0}); this.element.toggleClass('open'); this.element.empty(); if(!this.reopen){ this.active = false; } return this; }, open: function(num) { num = (num)? num : 0; var set = this.options.set[num]; this.active = num; this.inner[num].inject(this.element); if(typeof set.styles == 'object') { this.element.setStyles(set.styles); } this.start(set.open).chain( function() { this.element.addClass('open'); }.bind(this)); return this; } }); /*---------------------------------------------------- * モンスター ----------------------------------------------------*/ var Monster = new Class({ Extends:Fx.Morph, options: { 'name':'Monster', 'exp':0,//経験値 'type':'',//種族 'img':'', 'maxhp':100,//MAX体力 'status':{ 'lv':1, 'HP':100,//体力 'STR':5,//力 'VIT':5,//持久力 'DEX':5,//器用 'AGI':5,//敏捷 'INT':5,//かしこさ 'MND':5,//精神 'CHR':5 //魅力 }, 'condition':{//状態 'concent':0, //集中 'napping':0, //隙 'guard':0, //ガード 'confu':0, //混乱 'dark':0, //暗闇 'silent':0, //沈黙 'excite':0, //興奮 'sleep':0, //睡眠 'poison':0, //毒 'parayz':0 //麻痺 }, 'link':'cancel', 'pet':false, //プレイヤーが所有してたらtrue 'duration':200, 'transition':'back:inOut' }, initialize: function(options) { this.setOptions(options); var element = new Element('img', {'id':'monster','src':this.options.img}); this.parent(element, options); this.status = this.options.status; this.hp = this.options.status.HP; this.move = false; this.counter = 0; //出現後の経過時間カウント this.timer = null; //内部モーションタイマー }, getName: function() { return this.options.name; }, getLevel: function() { return this.options.status.lv; }, getImage: function() { return this.element; }, getType: function() { return this.options.type; }, getOption: function(key) { return this.options[key]; }, getHp : function() { return this.hp; }, setHp: function(hp) { this.hp = hp; return this; }, getCondition:function(key){ if(key){ return this.options.condition[key]; }else{ return this.options.condition; } }, setCondition:function(key,val){ if(val!==''){ this.options.condition[key] =val; }else{ this.options.condition = key; } }, getStatus: function(key) { if(key){ return this.status[key]; }else{ return this.status; } } }); var Motion = { //攻撃 slash:function(){ var $this = this; var effect = this.element.getPrevious('.effect'); if(effect){ effect.destroy(); } var div = new Element('div', {'class':'effect', 'styles':{'height':465, 'width':465,'opacity':0, 'position':'absolute','top':0,'left':0,'z-index':2}}); var divFx = new Fx.Morph(div, {duration:100,onComplete:function(){this.element.destroy();}}); div.inject(this.element, 'before'); var styles = this.element.getStyles('width','top','left'); this.setOptions({'transition':'cubic:Out','duration':200}); this.start({'width':360, 'top':-70, 'left':50}) .chain(function(){ $this.start({'top':20}); divFx.start({'background-color':'#f00', 'opacity':1}) .chain(function(){divFx.start({'opacity':0});}) .chain(function(){divFx.start({'opacity':1});}) .chain(function(){divFx.start({'opacity':0});}); }, function(){ $this.setOptions({'transition':'back:Out'}); $this.start(styles); }); }, //離れる distance:function(){ this.setOptions({ duration:300, 'transition':'quad:out' }); this.start({'left':130, 'width':200, 'top':70}); return this; }, //フェードアウト fadeOut:function(){ this.setOptions({'duration':1000,'transition':'quint:out'}); this.start({'opacity':0}).chain(function(){ this.element.destroy();}.bind(this)); return this; }, //だんだん離れて消える fadeAway:function(){ this.setOptions({'duration':2000,'transition':'quint:out'}); this.start({'left':180, 'width':100, 'top':150,'opacity':0}).chain(function(){ this.element.destroy();}.bind(this)); return this; }, //近づく approach:function(){ this.setOptions({ duration:300, 'transition':'quad:out' }); this.start({'left':110, 'width':240, 'top':50}); return this; }, //被ダメージ pain: function(damage) { this.setOptions({'duration':100,'transition':'bounce:inOut'}); var text = new Element('span', {'text':damage, 'class':'damage','morph':{'duration':1000,'transition':'cubic:out','onComplete':function(){this.element.destroy();}}}); text.inject(this.element,'before').morph({'opacity':0, 'top':160}); this.start({'left':120, 'width':220}) .chain( function() { this.start({'left':110, 'width':240}); }.bind(this) ); return this; }, //体力0 die:function(){ this.setOptions({'duration':1500,'transition':'quint:out', 'onComplete':function(){this.element.destroy();}}); this.start({'opacity':0}); } }; Monster.implement(Motion); /* サンプルのモンスター --------------------------------------------------*/ var Lion = new Class({ Extends: Monster, options:{ 'name':'フラワーライオン', 'exp':5000, 'type':'ネコ科', 'img':'http://www.cyberagent.co.jp/img/media/kayac/monster01.png', 'maxhp':400,//MAX体力 'status':{ 'lv':5, 'HP':400,//体力 'STR':10,//力 'VIT':10,//持久力 'DEX':10,//器用 'AGI':10,//敏捷 'INT':10,//かしこさ 'MND':10,//精神 'CHR':10 //魅力 } }, initialize: function(options) { this.parent(options); } }); /*---------------------------------------------------- * プレイヤー ----------------------------------------------------*/ var Player = new Class({ Implements: [Options], options: { 'name': 'Player', 'exp':0, 'maxhp':100, 'status':{ 'lv':1, 'HP':100,//体力 'VIT':5, 'STR':5,//力 'DEX':5,//器用 'AGI':5,//敏捷 'INT':5,//かしこさ 'MND':5,//精神 'CHR':5 //魅力 }, 'pets':[], 'items':[] }, initialize: function(options) { this.setOptions(options); this.pets = this.options.pets; this.petIndex = 0; this.activePet = this.pets[this.petIndex];//戦闘中のペット }, getName: function() { return this.options.name; }, getLv: function() { return this.options.status.lv; }, getStatus: function() { return this.options.status; }, getHp: function() { return this.status.hp; }, getItems: function() { return this.options.items; }, setItem: function(i, num) { this.options.items[i].num = num; }, getPets: function() { return this.pets; }, getActive: function() { return this.activePet; }, setPetIndex: function(num) { this.petIndex = num; }, setActive: function(i) { this.activePet = this.pets[i]; }, pet: function() { return this.getActive(); } }); var Versus = new Class({ setVersus: function(pet, npc) { this.pet = pet; this.npc = npc; }, versusGuard:function(how){ switch(how){ case 1: this.npc.distance(); this.npc.setCondition('guard', 1); this.ui.message.showInOut(this.npc.getName()+ ' はガードの構え'); break; default: this.npc.approach(); this.npc.setCondition('guard', 0); this.ui.message.showInOut(this.npc.getName()+ ' はガードを解いた'); break; } }, versusAttack:function(to){ var $this = this; var s = (to=='npc') ? 'pet':'npc'; var mName = (to=='npc') ? this.pet.getName():this.npc.getName(); var tName = (to=='npc') ? this.npc.getName():this.pet.getName(); this.versusAnim = new Chain(); this.versusAnim.chain( function(){ $this[s].move = true; if(to=='npc'){ $this.addLog('attack start', mName + ' に攻撃を指示'); $this.ui.message.showInOut(mName + ' に攻撃を指示'); } this.callChain.delay(1000, this); }, function(){ $this.ui.message.show(mName + ' の攻撃!'); $this.addLog('attack', mName + ' は ' + tName + ' に攻撃した'); this.callChain.delay(1000, this); }, function(){ var result = $this.decide(s, to, $this[s].getStatus()); if(to == 'npc'){ $this.setScope(); }else{ $this.setStatus(); } if(result.dmg > 0){ $this.addLog('attack', tName + 'に'+result.dmg+'のダメージ'); $this.ui.message.highlight( tName + 'に'+result.dmg+'のダメージ', ['rgba(255, 0, 0, 0.7)','rgba(0, 0, 0, 0.5)','rgba(255, 0, 0, 0.7)','rgba(0, 0, 0, 0.5)']); }else{ $this.addLog('attack miss', tName + ' は攻撃を回避した'); $this.ui.message.showInOut( tName + ' は攻撃を回避!'); } var d = 3000 - $this[s].getStatus('AGI')*80; this.callChain.delay(d, this); }, function(){ if($this[to].getHp() > 0){ $this[s].move = false; }else{ $this.versusAnim.clearChain(); if(to == 'npc'){ $this.defeat(); }else{ $this.gameOver(); } return; } } ); this.versusAnim.callChain(); }, decide:function(s, to, status){ var dmg = this.calcAtk(status) - this.calcDfn(status.VIT, this[s].getLevel(), this[to].getCondition('guard')); var hit = this.calcHit(s, to); if(hit === 0) { return {'dmg':0, 'hp':this[to].getHp()}; }else if(hit <=10){ dmg = Math.floor(dmg/2 - Math.random()); } var point = this[to].getHp() - dmg; if(point<=0){ point = 0; } this[to].setHp(point); if(to=='npc'){ this[to].pain(dmg); }else{ this[s].slash(); } return {'dmg':dmg, 'hp':point}; }, //攻撃力 calcAtk:function(status){ return Math.floor((((status.STR * 0.7) + (status.DEX * 0.3)) - Math.random()) * status.lv); }, //防御 calcDfn:function(vit, lv, guard){ var d = Math.floor(vit/2 + lv + (guard * 20 - Math.random())); return d; }, //命中率 calcHit:function(s,to){ var m = Math.floor(Math.sqrt(this[s].getStatus('DEX')) - this[to].getStatus('AGI')*2)+100; var h = Math.floor(Math.random() * m); return h; } }); /*---------------------------------------------------- * アクション ----------------------------------------------------*/ var Action = new Class({ //逃げる escape: function(success) { var $this = this; this.showModeTip('battle','Escape Mode'); this.ui.message.show('逃走方向を指示してください <strong class="confirm"><span class="yes">×</span> でキャンセル</strong>'); this.gesture.clearGesture(); this.console.close(); var successEsc = function(){ clearTimeout($this.monster.timer); clearTimeout($this.player.pet().timer); $this.versusAnim.clearChain(); $this.monster.fadeAway(); $this.layer.scope.fade(0); $this.ui.message.show($this.monster.getName()+'の前から逃げ出した'); $this.addLog('escape success', $this.monster.getName()+'の前から逃げ出した'); }; var escapeMiss = function(){ $this.addLog('escape miss', $this.player.getName()+' は 逃走に失敗'); $this.ui.message.showInOut(' 逃げられない!'); $this.versusAnim.clearChain(); $this.versusAttack('pet'); }; var n = [2,4,6,7,8,9]; var cmd = { 1:{ 3:this.battle.bind(this) }, 3:{ 1:this.battle.bind(this) }, 2:escapeMiss, 4:escapeMiss, 6:successEsc, 7:escapeMiss, 8:escapeMiss, 9:successEsc }; this.gesture.addGestures(cmd); }, //アイテム使用 useItem: function() { this.showModeTip('battle','Inventory'); this.console.toggle(3, true); }, //モンスター変更 changeMonster: function() { this.showModeTip('battle','Change Monster'); this.console.toggle(2, true); }, //つかまえる(モンスター衰弱時・隙がtrueの時にコマンド発生) capture : function() { this.showModeTip('battle','Capture Mode'); }, /** * たたかう */ battle: function() { var $this = this; var timer = 0; var petName = this.player.pet().getName(); var monsName = this.monster.getName(); var checkActive = function(){ if(!$this.player.pet().move && $this.player.pet().getCondition('guard')===0){ $this.ui.status.name.className = 'name star'; }else{ $this.ui.status.name.removeClass('star'); } }; this.player.pet().timer = checkActive.periodical(500); this.ui.message.hide(); this.player.pet().setCondition('guard',0); if(this.player.pet().getCondition('guard')===0) { this.monster.approach(); } //ログメッセージ this.addLog('battle start', petName + ' は '+monsName+' と 戦闘を開始'); this.showModeTip('battle','Battle Mode'); this.console.setWindow(0, { 'content':null, 'button':'Command', 'open':{'bottom':40,'opacity':1}, 'styles':{ 'height':120, 'background':'url(http://demo.webtecnote.com/nyaos/images/cmd-battle.png) no-repeat center bottom', 'border':0 } }); this.console.toggle(0, true); //通常攻撃 var attack = function() { $this.showModeTip('battle','Battle Mode'); if( $this.player.pet().getCondition('guard')) { $this.addLog('battle error', 'ガード中は攻撃できない'); $this.ui.message.showInOut( 'ガード中は攻撃できない'); return; }else if($this.player.pet().move || $this.monster.move){ return; } $this.versusAttack('npc'); }; //特殊攻撃 var skill = function() { $this.showModeTip('battle','Battle Mode'); $this.addLog('skill start', petName + ' に 百烈拳を指示'); $this.ui.message.showInOut(petName + ' に 百烈拳を指示'); }; //ガード? var guard = function() { $this.showModeTip('battle','Battle Mode'); $this.addLog('guard start', petName + ' に ガードを指示'); $this.ui.message.showInOut(petName + ' に ガードを指示'); $this.player.pet().setCondition('guard', 1); $this.monster.distance(); }; var escapeMiss = function(){ $this.showModeTip('battle','Battle Mode'); $this.addLog('escape miss', $this.player.getName()+' は 逃走に失敗'); $this.ui.message.showInOut(' 逃げられない!'); }; //前進 var advance = function(){ if( $this.player.pet().getCondition('guard')) { $this.addLog('guard off', petName + ' に ガード解除を指示'); $this.ui.message.showInOut(petName + ' に ガード解除を指示'); $this.monster.approach(); $this.player.pet().setCondition('guard', 0); } }; //バトル中コマンド var cmd = { 6:attack, 1:{ 3:skill }, 3:{ 1:skill }, 8:advance, 2:guard, 89632:this.escape.bind(this, true), 8963:this.escape.bind(this, true), 8932:escapeMiss, 8631:escapeMiss, 9632:escapeMiss, 963:escapeMiss, 932:escapeMiss, 632:escapeMiss, 698:this.useItem.bind(this) }; //ジェスチャーセット this.gesture.addEvent('complete', function(){ if(this.console.active==1){ this.updateLog(this.console.element, this.console.inner[1]); } }.bind(this)); this.gesture.addGestures(cmd); } }); /*---------------------------------------------------- * メイン ----------------------------------------------------*/ var Gyaos = this.Gyaos = new Class({ Implements: [Chain, Events, Options, Action,Versus], options: { layer : { 'container':$('container'), 'main':$('main'), 'canvas':$('canvas') } }, initialize: function(options) { this.subject = this.subject || this; this.setOptions(options); this.gamelog = [];//ログ this.layer = this.options.layer;//レイヤー this.versus = null;//クラス var message = new Element('div',{'id':'message'}); message.fade('hide').inject(this.layer.container,'top'); this.ui = { 'message':new Dialog(message), 'status':{}, 'scope':{} }; //モンスデータ this.monsterData = [ new Lion() ]; //プレイヤー this.player = new Player({ 'name': 'ああああ', 'exp':10000, 'status':{ 'lv':10, 'HP':500,//体力 'STR':25,//力 'VIT':25, 'DEX':25,//器用 'AGI':25,//敏捷 'INT':25,//かしこさ 'MND':25,//精神 'CHR':25 //魅力 }, 'items':[ {'name':'薬草', 'num':5}, {'name':'万能薬', 'num':3}, {'name':'落とし穴', 'num':1} ], 'pets':[ new Lion({ 'name':'ライオン丸', 'exp':10000, 'maxhp':400, 'img':'http://www.cyberagent.co.jp/img/media/kayac/monster01.png', 'status':{ 'lv':5, 'HP':400,//体力 'STR':14,//力 'VIT':8,//持久力 'DEX':8,//器用 'AGI':12,//敏捷 'INT':8,//かしこさ 'MND':5,//精神 'CHR':10 //魅力 }, 'condition':{//状態 'guard':1 //ガード }, 'pet':true }) ] }); this.gesture = new MoouseGesture(this.layer.canvas); this.console = new Console({ set:[ { 'className':'command', 'content':null, 'title':'マウスジェスチャーコマンド', 'button':'Command', 'open':{'bottom':38,'opacity':1}, 'styles':{ 'background':'url(http://demo.webtecnote.com/nyaos/images/cmd-1.png) no-repeat center top', 'height':120, 'border':0 } }, { 'className':'log', 'title':'ログ', 'content':this.getLogHTML(), 'button':'Log', 'open':{'bottom':38,'opacity':1}, 'styles':{'background':'rgba(255,255,255,0.3)','height':100,'border':'solid 1px rgba(255,255,255,0.45)','border-bottom':'solid 1px #000'} }, { 'className':'monster', 'title':'モンスター変更', 'content':this.monsterList(), 'button':'Monster', 'open':{'bottom':38,'opacity':1}, 'styles':{'background':'rgba(255,255,255,0.2)','height':100,'border':'solid 1px rgba(255,255,255,0.35)','border-bottom':'solid 1px #000'} }, { 'className':'item', 'title':'アイテム', 'content':this.setInventory(), 'button':'Item', 'open':{'bottom':38,'opacity':1}, 'styles':{'background':'rgba(255,255,255,0.2)','height':100,'border':'solid 1px rgba(255,255,255,0.35)','border-bottom':'solid 1px #000'} } ], show:0, onClose: function(el, inner) { }.bind(this), onOpen: function(el, inner, num) { switch(num) { case 1: this.updateLog(el, inner); break; case 2: inner.empty(); this.monsterList().inject(inner); new Element('div', {'id':'petList-nav', 'html':'<span class="current">●</span><span>○</span><span>○</span>'}).inject(inner); break; default: break; } }.bind(this) }); this.createLayer(); this.encount(); }, //レイヤー作成 createLayer: function() { //モードチップ var mode = new Element('div',{'id':'mode'}); mode.inject(this.layer.container); this.layer['mode'] = mode; //ステータス var status = new Element('div',{'id':'status'}); status.inject(this.layer.container); this.layer['status'] = status; this.createStatusElement(); }, //敵ステ createScope:function(){ var scope = new Element('div', {'id':'scope'}); var name = new Element('div', {'class':'name', 'text':this.monster.getName()}); var hp = new Element('span', {'class':'hp'}); var count = new Element('span',{'class':'count'}); var bar = new Element('span', {'class':'bar'}); this.layer['scope'] = scope; this.ui.scope['name'] = name; this.ui.scope['hp'] = hp; this.ui.scope['count'] = count; this.ui.scope['bar'] =bar; scope.fade('hide').inject(this.layer.main); name.inject(scope); bar.inject(hp); count.inject(hp); hp.inject(scope); this.ui.scope['barx'] = this.ui.scope.bar.getSize().x; return this; }, setScope:function(){ var pet = this.monster; var barvars = this.getHpCoordinates(this.ui.scope.barx, pet); this.ui.scope.count.set('text',pet.getHp()); //this.ui.scope.level.set('text', 'Lv' +pet.getLevel()); this.ui.scope.hp.addClass(barvars.className); this.ui.scope.bar.setStyle('width', barvars.width); this.ui.scope.bar.set('title', 'Max:'+pet.getStatus('HP')+'('+barvars.par+'%)'); return this; }, //ステータスの中身作成 createStatusElement: function() { var wrap = new Element('div', {'id':'info'}); var hp = new Element('div',{'class':'hp'}); var lv = new Element('span', {'class':'level'}); var count = new Element('span',{'class':'count'}); var bar = new Element('span', {'class':'bar'}); var name = new Element('div',{'class':'name', 'html':'<strong>'+this.player.pet().getName()+'</strong>'}); this.ui.status['hp'] = hp; this.ui.status['level'] = lv; this.ui.status['count'] = count; this.ui.status['bar'] =bar; this.ui.status['name'] =name; name.inject(wrap); lv.inject(name,'top'); bar.inject(hp); count.inject(hp); hp.inject(wrap); wrap.inject(this.layer.status); this.ui.status['barx'] = bar.getSize().x; return this; }, //HPの割合とか getHpCoordinates: function(x, pet) { var par = (pet.getHp()/pet.getStatus('HP')).toFloat(1); var w = x * par; var className = 'good'; if(par <= 0.25) { className = 'danger'; } else if(par <= 0.50) { className = 'attention'; } return {'x': x, 'par': (par*100), 'width':w, 'className': className}; }, /** * ステータスのセッター * * HP class : good -> attention -> danger */ setStatus : function() { var pet = this.player.pet(); var barvars = this.getHpCoordinates(this.ui.status.barx, pet); this.ui.status.count.set('text',pet.getHp()); this.ui.status.level.set('text', 'Lv' +pet.getLevel()); this.ui.status.hp.addClass(barvars.className); this.ui.status.bar.setStyle('width', barvars.width); this.ui.status.bar.set('title', 'Max:'+pet.getStatus('HP')+'('+barvars.par+'%)'); }, //デフォルトのジェスチャーコマンド setDefaultGesture: function() { var command = { 8:this.battle.bind(this), 2:this.escape.bind(this), 6:this.changeMonster.bind(this), 4:this.useItem.bind(this) }; this.gesture.addGestures(command); }, /** * #container 背景色のセット * 20 - 5 : Night * 6 - 10 : Morning * 11 - 16 : Daytime * 17 - 19 : Evening */ setBackground: function() { var time = new Date().getHours(); if(time >= 0 && time <= 5) { this.layer.container.addClass('night'); } else if(time >=6 && time <= 10) { this.layer.container.addClass('morning'); } else if(time >= 11 && time <= 16) { this.layer.container.addClass('daytime'); } else if(time >= 17 && time <= 19) { this.layer.container.addClass('evening'); } else { this.layer.container.addClass('night'); } }, //ログの追加 addLog: function(key, text) { this.gamelog.push([new Date().getTime(), key, text]); }, /** * ログ生成 */ getLogHTML : function() { var log = new Element('ul', {'class': 'log'}); this.gamelog.each( function(item, i) { var date = new Date(); date.setTime(item[0]); new Element('li', {'text':item[2], 'class': item[1]}).inject(log); }); return log; }, updateLog:function(parent, inner){ inner.empty(); var mt = parent.retrieve('mt'); var log = this.getLogHTML(); log.set({ 'tween':{ 'duration':300, 'property':'margin-top', onComplete:function(e){ parent.store('mt', e.getStyle('margin-top').toInt()); }.bind(this)} }); log.setStyle('margin-top', mt).inject(inner); var h = log.getSize().y - inner.getSize().y; if(h > 0){ log.tween(-h); } }, /** * モードチップ */ showModeTip: function(className, text) { this.layer.mode.set('html','<small class="mode '+className+'">'+text+'</small><strong>'+this.player.getName()+'</strong>'); this.layer.mode.addClass(className); this.layer.mode.fade(1); }, //アイテム袋 setInventory: function() { var $this = this; var items = new Element('div.itemList'); this.player.getItems().each( function(item,i) { var li = new Element('a',{'href':'#','html': '<span class="name">' + item.name + '</span><span class="num">'+ item.num+'</span>'}); li.addEvent('click', function() { var i = this.retrieve('i'); var n = this.retrieve('stock'); if(n===0) return; n--; $this.player.setItem(i, n); this.store('stock', n); this.getElement('.num').set('text', n); }); li.store('i', i); li.store('stock', item.num); li.inject(items); }); return items; }, //モンスターリスト monsterList: function() { var $this = this; var table = new Element('table',{'class':'petList'}); var cmd = this.gesture.getGestures(); this.player.getPets().each( function(pet, i) { var tr = new Element('tr'); var th = new Element('th',{'class':'name', 'html':'<strong>'+pet.getName()+'</strong><span class="level">Lv'+pet.getLevel()+'</span><span class="type">'+pet.getType()+'</span>'}); th.setStyle('background-image', 'url('+pet.getOption('img')+')'); th.inject(tr); var petStatus = pet.getStatus(); var status = ''; Object.each(petStatus, function(val, key) { if(key == 'HP') return; status += '<small>' + key + '</small><em>' + val+'</em>'; }); var bar = new Element('span', {'class':'bar'}); var barvars = $this.getHpCoordinates(240, pet); var hp = new Element('div',{'class':'hp '+barvars.className, 'title': 'Max:'+pet.getStatus('HP')+'('+barvars.par+'%)'}); var count = new Element('span',{'class':'count', 'text':pet.getHp()}); bar.setStyle('width',barvars.width).inject(hp); count.inject(hp); var td = new Element('td',{'class':'info', 'html':'<div class="status">'+status+'</div>'}); hp.inject(td, 'top'); td.inject(tr); tr.inject(table); var change = function(i) { //this.player.setActive(i); $this.ui.message.showInOut('変更しました '); $this.gesture.addGestures(cmd); $this.console.toggle(0); }; var cancel = function(i) { $this.ui.message.hide(); $this.gesture.addGestures(cmd); $this.console.toggle(0); }; tr.addEvent('click', function(e) { var table = this.getParent('table'); dispose = table.getChildren().dispose(); e.target.getParent('tr').addClass('selected').inject(table); var confirm = new Element('div',{'class':'confirm'}); $this.ui.message.show('このモンスターに変更しますか? <strong class="confirm"><span class="yes"">YES ↑</span> <span class="no">NO ↓</span></strong> '); var command = { 8:change.bind(i), 2:cancel.bind(i) }; $this.gesture.addGestures(command); }); }); return table; }, //エンカウント encount : function() { this.monster = this.monsterData.getRandom(); this.setStatus(); this.createScope(); this.layer.scope.fade(1); this.setScope(); this.showModeTip('battle','Mode Choice'); this.monster.getImage().inject(this.layer.main); this.setBackground(); this.addLog('encount', this.monster.getName()+' が現れた!'); //コマンドセット this.setDefaultGesture(); this.ui.message.showInOut(this.monster.getName()+' が現れた!'); this.setVersus(this.player.pet(), this.monster); //アニメーション開始 this.monster.start({'opacity':[0,1],'top':[-50,70]}); this.moveNpc(); }, moveNpc:function(){ var $this = this; this.monster.timer = 0; var normal = function(){ if($this.player.pet().getHp() > 0 && (!$this.player.pet().move && !$this.monster.move)){ $this.versusAttack('pet'); }else{ return; } }; $this.monster.timer = normal.periodical(2000); }, defeat:function(){ clearTimeout(this.monster.timer); clearTimeout(this.player.pet().timer); if(this.monster.hp <= 0){ this.monster.die(); this.layer.scope.fade(0); this.ui.message.showInOut(this.monster.getName()+' を倒した'); this.addLog('defeat', this.player.pet().getName() +' は ' + this.monster.getName()+' を倒した'); this.setDefaultGesture(); } }, gameOver:function(from){ clearTimeout(this.monster.timer); clearTimeout(this.player.pet().timer); this.ui.message.showInOut(this.player.pet().getName()+' は力尽きた…'); this.addLog('defeat', this.player.pet().getName() +' は ' + this.monster.getName()+' に倒された'); this.setDefaultGesture(); this.monster.fadeOut(); this.layer.scope.fade(0); } }); new Gyaos(); })(document.id); }); <div id="container"> <div id="main"></div> <canvas id="canvas"></canvas> </div> <script type="text/javascript" src="https://www.google.com/jsapi"></script> body { font-size:13px; margin:0; padding:0; } ul { padding:0; margin:0; } li { list-style:none outside; } em { font-style:normal; } a{ text-decoration:none; color:#fff; overflow:hidden; outline:none; } #canvas { position:absolute; top:0; left:0; width:465px; height:465px; z-index:4; } #container{ position:relative; width:465px; height:465px; margin:0 auto; background-color:#000; overflow:hidden; -moz-user-select: none; -khtml-user-select: none; -webkit-user-select: none; user-select: none; } .night{ background: -moz-linear-gradient(top, #160072 0%, #07114F 46%, #000000 48%, #000528 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#160072), color-stop(46%,#07114F), color-stop(48%,#000000), color-stop(100%,#000528)); } .morning{ background: -moz-linear-gradient(top, #3989DD 0%, #0D2299 46%, #0D1242 48%, #002766 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#3989DD), color-stop(46%,#0D2299), color-stop(48%,#0D1242), color-stop(100%,#002766)); } .daytime{ background: -moz-linear-gradient(top, #5EC9FF 0%, #D1ECFF 46%, #417A34 48%, #578C47 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#5EC9FF), color-stop(46%,#D1ECFF), color-stop(48%,#417A34), color-stop(100%,#578C47)); } .evening{ background: -moz-linear-gradient(top, #160072 0%, #BA1310 46%, #000000 48%, #3F0B00 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#160072), color-stop(46%,#BA1310), color-stop(48%,#000000), color-stop(100%,#3F0B00)); } /* メッセージダイアログ ---------------------------------------------*/ #message { width:380px; background:rgba(0,0,0,0.5); color:#fff; padding:10px; position:absolute; top:10px; left:50%; margin-left:-200px; -webkit-border-radius:8px; -moz-border-radius:8px; border-radius:8px; z-index:2; } /* メイン ------------------------------------------------------- */ #main { width:100%; height:100%; font-size:12px; } #main img#monster { position:absolute; width:200px; opacity:0; left:130px; z-index:1; height:auto; } #scope { background: -moz-linear-gradient(top, #4c4c4c 0%, #595959 4%, #666666 12%, #474747 27%, #2c2c2c 44%, #000000 45%, #111111 71%, #2b2b2b 90%, #1c1c1c 96%, #131313 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#4c4c4c), color-stop(4%,#595959), color-stop(12%,#666666), color-stop(27%,#474747), color-stop(44%,#2c2c2c), color-stop(45%,#000000), color-stop(71%,#111111), color-stop(90%,#2b2b2b), color-stop(96%,#1c1c1c), color-stop(100%,#131313)); border:1px solid rgba(0,0,0,0.6); position:absolute; right:30px; top:60px; width:150px; -moz-border-radius:4px; border-radius:4px; } #scope .name { font-size:85%; color:#fff; margin:5px 5px 2px 5px; } #scope .hp { display:block; margin:0 5px 5px 5px; line-height:1; height:10px; background:url(http://demo.webtecnote.com/nyaos/images/bg_bar.png) no-repeat left bottom; -webkit-background-size:100px; -moz-background-size:100px; -o-background-size:100px; background-size:100px; overflow:hidden; } #scope .bar{ width:100px; } #main .damage{ font-size:30px; color:#ff0000; font-weight:bold; font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; position:absolute; top:180px; left:270px; z-index:2; } /*プレイヤー名とモード表示 -------------------------------------------------*/ #mode { position:absolute; border:solid 1px #101010; color:#fff; bottom:2px; left:2px; color:#efefef; width:105px; height:33px; text-align:center; background: -moz-linear-gradient(top, #24252E 0%, #000000 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#24252E), color-stop(100%,#000000)); z-index:7; } #mode strong { font-weight:normal; display:inline-block; margin-top:10px; } #mode .mode { display:block; position:absolute; top:-18px; left:0; line-height:15px; padding:0 5px; color:#6f6f6f; background:#070709; border:solid 1px #3D3D3D; font-size:9px; font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; -moz-border-radius:4px 4px 0 0; border-radius:4px 4px 0 0; } /* ステータス ------------------------------------------------------ */ #status { position:absolute; left:0; bottom:0; background:#24262f; border-top:solid 1px #3d3d3d; color:#fff; height:37px; width:355px; padding-left:115px; z-index:6; } /* 使役中のモンスター情報 */ #info { width:210px; overflow:hidden; } #info .name { margin:3px 0; } #info .name.star strong:after { content:' Ready!'; font-size:85%; color:#FFFF00; display:inline; font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; font-weight:normal; } .level { display:inline-block; padding:0 3px; margin-right:5px; font-size:85%; -moz-border-radius: 3px; border-radius: 3px; /* background: -moz-linear-gradient(top, #F8D04A 0%, #ED9017 70%, #ED7717 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#F8D04A), color-stop(70%,#ED9017), color-stop(100%,#ED7717)); text-shadow: 0px 0px 1px #b35e13; */ background: -moz-linear-gradient(top, #cedce7 0%, #596a72 100%); /* firefox */ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#cedce7), color-stop(100%,#596a72)); /* webkit */ text-shadow: 0px 0px 1px rgba(0,0,0,1); font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; } #info .hp , .petList .hp{ line-height:1; height:10px; background:url(http://demo.webtecnote.com/nyaos/images/bg_bar.png) no-repeat left bottom; -webkit-background-size:180px; -moz-background-size:180px; -o-background-size:180px; background-size:180px; } #info .hp .bar { height:8px; width:180px; display:inline-block; } .hp .count { display:inline-block; font-size:77%; line-height:1; font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; height:10px; vertical-align:top; float:right; } .good .count { color:#0D94D6; } .attention .count { color:#F8D800; } .danger .count {color:#EA0000} .good .bar { border:solid 1px #066999; background: -moz-linear-gradient(top, #0894D6 0%, #0D94D6 20%, #057DC2 20%, #0988CC 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#0894D6), color-stop(20%,#0D94D6), color-stop(20%,#057DC2), color-stop(100%,#0988CC)); -webkit-box-shadow: inset -1px -1px 1px rgba(0,180,255,1); -moz-box-shadow: inset -1px -1px 1px rgba(0,180,255,1); box-shadow: inset -1px -1px 1px rgba(0,180,255,1); } .attention .bar { border:solid 1px #c29b00; background: -moz-linear-gradient(top, #FCFAC0 0%, #FCE94D 20%, #F8D800 20%, #FFDE00 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#FCFAC0), color-stop(20%,#FCE94D), color-stop(20%,#F8D800), color-stop(100%,#FFDE00)); -webkit-box-shadow: inset -1px -1px 1px rgba(255,240,0,1); -moz-box-shadow: inset -1px -1px 1px rgba(255,240,0,1); box-shadow: inset -1px -1px 1px rgba(255,240,0,1); } .danger .bar { border:solid 1px #870404; background: -moz-linear-gradient(top, #F03B3B 0%, #F11B1C 20%, #EA0000 20%, #C80000 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#F03B3B), color-stop(20%,#F11B1C), color-stop(20%,#EA0000), color-stop(100%,#C80000)); -webkit-box-shadow: inset -1px -1px 1px #e80101; -moz-box-shadow: inset -1px -1px 1px #e80101; box-shadow: inset -1px -1px 1px #e80101; } /* コンソール ---------------------------------------------------- */ #console{ position:absolute; width:100%; bottom:10px; left:0; height:150px; overflow:hidden; background-repeat:no-repeat; background-position:center bottom; z-index:5; } #console .inner { position:relative; overflow:hidden; margin:10px; height:80px; } /* コンソールのボタン ---------------------------------------------------- */ #console-controller { position:absolute; right:3px; bottom:3px; z-index:7; height:31px; } #console-controller:active{ z-index:10 } .consoleButton { display:inline-block; color:rgba(255,255,255,0.5); margin-left:3px; cursor:pointer; height:31px; width:31px; background-repeat:no-repeat; background-position:left top; } .consoleButton span{ visibility:hidden; } .consoleButton:focus, .consoleButton:hover { background-position:left -31px !important; } .consoleButton.command{ background:url(http://demo.webtecnote.com/nyaos/images/command.png); } .consoleButton.log{ background:url(http://demo.webtecnote.com/nyaos/images/log.png); } .consoleButton.monster{ background:url(http://demo.webtecnote.com/nyaos/images/monster.png); } .consoleButton.item{ background:url(http://demo.webtecnote.com/nyaos/images/item.png); } /* .consoleButton { line-height:24px; height:24px; padding:0 0.6em; margin-left:3px; font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; font-size:85%; cursor:pointer; -webkit-border-radius:5px; -moz-border-radius:5px; border-radius:5px; background: -moz-linear-gradient(top, rgba(255,255,255,0.1) 0%, rgba(0,0,0, 0.3) 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,0.1)), color-stop(100%,rgba(0,0,0, 0.3))); } .consoleButton:hover { background: -moz-linear-gradient(top, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0.1) 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,0.3)), color-stop(100%,rgba(255,255,255,0.1))); } */ /* ログ ----------------------------------------------------- */ .log { color:#efefef; } .log li { font-size:93%; padding: 0 0 5px 0; } .log .encount { color: #EF0E0E } /* アイテムリスト ------------------------------------------------------- */ .itemList { color:#efefef; } .itemList a { margin:0 2px 5px 2px; display:inline-block; overflow:hidden; } .itemList .name { display:inline-block; background-color:rgba(62,111,87, 1); padding:2px 5px; -webkit-border-radius:3px 0 0 3px; -moz-border-radius:3px 0 0 3px; border-radius:3px 0 0 3px; } .itemList .num { display:inline-block; background-color:rgba(20,20,20,0.8); padding:2px 5px; -webkit-border-radius:0 3px 3px 0; -moz-border-radius:0 3px 3px 0; border-radius:0 3px 3px 0; } .itemList a:focus .name, .itemList a:hover .name{ background-color:rgba(102,151,127, 1); } .itemList a:focus .num, .itemList a:hover .num{ background-color:rgba(60,60,60,0.8); } /* ペットリスト -------------------------------------------------*/ .petList { color:#fff; width:100%; border-collapse:collapse; cursor:pointer; } .petList .name { background-repeat:no-repeat; background-position:-15px -30px ; -webkit-background-size: 80px auto ; -moz-background-size: 80px auto ; -o-background-size: 80px auto ; background-size: 80px auto ; height:50px; padding:0 10px 0 60px; background-color:rgba(0,0,0,0.5); -webkit-border-radius:5px 0 0 5px; -moz-border-radius:5px 0 0 5px; border-radius:5px 0 0 5px; font-weight:normal; width:35%; text-align:left; } .petList .name strong { display:block; margin-bottom:5px; } .petList .type{ font-size:77%; color:#9F9F9F; } .petList .info { padding:5px 10px; background-color:rgba(0,0,0,0.2); -webkit-border-radius: 0 5px 5px 0; -moz-border-radius: 0 5px 5px 0; border-radius: 0 5px 5px 0; font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; } /* HPのバー 一部ペットと共通 */ .petList .hp{ line-height:1; margin-bottom:5px; height:10px; background:url(http://demo.webtecnote.com/nyaos/images/bg_bar.png) no-repeat left bottom; width:269px; -webkit-background-size:240px; -moz-background-size:240px; -o-background-size:240px; background-size:240px; } .hp .bar { height:10px; width:240px; display:inline-block; line-height:1; } .petList .info small { display:inline-block; color:#cEDCE7; font-size:77%; } .petList .info em { margin-right:8px; } .petList .info em:last-child{ margin:0; } #petList-nav { text-align:center; color:#596A72; font-size:85%; margin-top:10px; } #petList-nav span { cursor:pointer; } .confirm { display:inline-block; margin-left:2em; } .confirm .yes { color:#67FF5F } .confirm .no { color:#FF885F; } use an iframe compat browser, deer Play on jsdo.it games Share Embed QR Tag Download Complete! Description どんなゲームですか? マウスジェスチャーでモンスターに行動指示を出します アイテムは数が減るだけです。 時間帯で背景が変化します。 Control Device スマートフォンコントローラー jsdo.it WebSocket Controller» マウス キーボード タッチデバイス Fullscreen 有効 無効 jsdo.it games から削除する Submit Tweet style Design view Code view code <script type="text/javascript" src="http://jsdo.it/blogparts/wsmR/js?view=design"></script><p class="ttlBpJsdoit" style="width: 465px; margin: 0; text-align: right; font-size: 11px;"><a href="http://jsdo.it/Tenderfeel/wsmR" title="forked from: GYAOS_sample">forked from: GYAOS_sample - jsdo.it - share JavaScript, HTML5 and CSS</a></p> CSS3 MooTools Tweet twitter Tags CSS3 MooTools Favorite by hoge123 asus4 xor cuddlephish Forked sort new page view favorite forked forked from: forked from: GYAO.. keis1979 00 111views 1466/6/536 CSS3 MooTools