質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

7986閲覧

【js】親オブジェクトのプロパティを使いたい

mijinko889

総合スコア33

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2018/11/11 11:19

編集2018/11/12 11:10

###前提

javascriptで記述した以下のようなコードがあるとします。
制約条件
・パーティに同じ名前のキャラは一人しか編成できない
・パーティには控えはいない
・キャラは違う処理をするスキルを持つ
・ダメージを受けた時特有の反応をするキャラもいる

CharacterData.js

1characters ={ 2 "主人公":{ 3 partyid:0, 4 AttackDate:{ 5 discription:"ターゲットに通常攻撃", 6 count:10, 7 Atk:function(){ 8 getDamage = partystetas[characters["主人公"].partyid].Pow; 9 Damage(standEnemy[characters["主人公"].partyid],getDamage); 10 //console.log("aaa"); 11 EnemySetting(characters["主人公"].partyid); 12 console.log(enemystetas.length); 13 }, 14 }, 15 SapportDate:{ 16 discription:"SCORE上昇量1%up", 17 Sap:function(){ 18 if(updatecounter % fps_*3 === 0){ 19 for(var i=0;i<4;i++){ 20 if(partystetas[i].Hp < partystetas[i].maxHP) 21 partystetas[i].Hp += 50; 22 } 23 } 24 } 25 }, 26 Dam:function(){ 27 Damage(this.partyid,getDamage); 28 }, 29 Date:new CharacterData( 30 "img/characters/sprite_char1.jpg",//イメージuri 31 0,//ID 32 "主人公",//表示名--パーティーデータ取得時に主キーにしてユーザー毎のキャラステータスを取得? 33 1100,//最大HP 34 1500,//攻撃力 35 800,//防御力 36 "atk",//タイプ 37 "ヒューマン",//種族 38 "SR"//レアリティ 39 ), 40 }, 41 "朱雀":{ 42 partyid:0, 43 AttackDate:{ 44 discription:"ターゲットに通常攻撃", 45 count:10, 46 Atk:function(){ 47 }, 48 }, 49 SapportDate:{ 50 discription:"SCORE上昇量1%up", 51 Sap:function(){ 52 if(updatecounter % fps_*5 === 0){ 53 score_ += 10; 54 } 55 } 56 }, 57 Dam:function(){ 58 Damage(this.partyid,getDamage); 59 }, 60 Date:new CharacterData( 61 "img/characters/sprite_char2.jpg", 62 1, 63 "ヒロイン", 64 1010, 65 1020, 66 200, 67 "enh", 68 "ヒューマン", 69 "SR" 70 ), 71}, 72 "白虎":{ 73 partyid:0, 74 AttackDate:{ 75 discription:"ターゲットに通常攻撃", 76 count:10, 77 Atk:function(){ 78 console.log("aaap"); 79 }, 80 }, 81 SapportDate:{ 82 discription:"SCORE上昇量5%up", 83 Sap:function(){ 84 if(updatecounter % fps_*3 === 0) 85 member_combCount[characters["プレイヤー"].partyid]+=1; 86 } 87 }, 88 Dam:function(){ 89 Damage(this.partyid,getDamage); 90 }, 91 Date:new CharacterData( 92 "img/characters/sprite_char3.jpg", 93 1, 94 "プレイヤー", 95 1010, 96 1020, 97 200, 98 "enh", 99 "ヒューマン", 100 "SR" 101 ), 102 }, 103 "玄武":{ 104 partyid:0, 105 AttackDate:{ 106 discription:"ターゲットに通常攻撃", 107 count:10, 108 Atk:function(){ 109 console.log("捕ったど~"); 110 }, 111 }, 112 SapportDate:{ 113 discription:"SCORE上昇量5%up", 114 Sap:function(){ 115 //console.log("Support3"); 116 } 117 }, 118 Dam:function(){ 119 console.log("ダメージ受けたなり~"); 120 Damage(this.partyid,getDamage); 121 }, 122 Date:new CharacterData( 123 "img/characters/sprite_char3.jpg", 124 1, 125 "玄武", 126 1300, 127 1520, 128 300, 129 "def", 130 "オーガ", 131 "SSR" 132 ), 133 }, 134}; 135 136function EnemySetting(num){ 137 if(standEnemy[num].Hp <= 0){ 138 if(enemystetas.length > 0){ 139 standEnemy[num]=(enemystetas.shift()); 140 standEnemy[num].partyid = num; 141 } 142 } 143}

キャラ(charaClassオブジェクト)ごとに違うスキル、ステータスを保持しており、戦闘シーンでのメイン処理では分岐を使わず同じ呼び出し方で書きたいと思ってたどり着いたのが現状の書き方ですね。「キャラの持つスキルの内容」を一纏めにするためにAttackDateを作っています。

キャラを作成するのと同じようにスキルも作成しようと思ったのですが、引数にfunction()を渡すコールバック処理をcharacterclassオブジェクトに作っています。

characterClass.js

1var 2member_size_X = member_size_Y=32,//サイズ 3partyspritesize_W=288,partyspritesize_H=32, 4Damagestetas={ 5 damage_:0, 6 type_:"ATK"//攻撃者のタイプ 7}, 8getDamage=0; 9//キャラクターデータクラス 10function CharacterData(img,id,name,maxhp,maxpow,maxdeff,type,race,rera){ 11 this.img=new Image(), 12 this.img.src=img; 13 this.id=id; 14 this.name=name; 15 this.Hp=maxhp; 16 this.Pow=maxpow; 17 this.Deff=maxdeff; 18 this.Type=type; 19 this.Race=race; 20 this.Rare=rera; 21 22 this.waitSprite = new AnimSprite(this.img,0,0,partyspritesize_W,partyspritesize_H,member_size_X,member_size_Y,3,1); 23 this.attackSprite= new AnimSprite(this.img,member_size_X*3,0,partyspritesize_W,partyspritesize_H,member_size_X,member_size_Y,3,1); 24 this.skillSprite= new AnimSprite(this.img,0,member_size_Y*2,partyspritesize_W,partyspritesize_H,member_size_X,member_size_Y,3,1); 25 this.damageSprite= new AnimSprite(this.img,0,member_size_Y*3,partyspritesize_W,partyspritesize_H,member_size_X,member_size_Y,3,1); 26 this.deadSprite= new AnimSprite(this.img,192,160,partyspritesize_W,partyspritesize_H,member_size_X,member_size_Y,3,1); 27 28 this.motionsprite= this.waitSprite ; 29 30 this.Atkfunction = function(atkfunc){ 31 atkfunc(); 32 }; 33 34 this.Damagefunction=function(damagefunc){ 35 damagefunc() 36 }; 37 38 this.Sapportfunction=function(sapportfunc){ 39 sapportfunc(); 40 }; 41} 42 43 44//基本的なダメージ処理 45var 46Damage = function(member,damage){ 47 member.Hp -= damage; 48}, 49//キャラ描画 50Characterdtaw = function(charax_,charay_,sprite_){ 51 sprite_.animdraw(ctx,charax_,charay_); 52}; 53 54function charinit(){//呼び出し方の例 55 var 56 i, 57 58 chara1 = characters["主人公"], 59 chara2 = characters["ヒロイン"]; 60 61 62 chara1.Date.Atkfunction(chara1.AttackDate.Atk); 63 chara2.Date.Sapportfunction(chara1.SapportDate.Sap); 64 65 66} 67 68function SetDamagest(Damagest,damage_,type_){ 69 Damagest.damage_ = damage_; 70 Damagest.type_ = type_; 71 72 return Damagest; 73} 74 75function DamageCol(stetas_){ 76 var getdamage; 77 getdamage = stetas_.damage_;//ダメージ計算 78 79 return getdamage; 80} 81 82

main.js

1var 2//////////////////////////////////////////////パーティオブジェクト///////////////////////////////////////////////////// 3party=[ 4 characters["主人公"], 5 characters["ヒロイン"], 6 characters["プレイヤー"], 7 characters["玄武"] 8],//4人 9partystetas=[], 10 11i=0, 12STEPTIME = 10, 13step=0; 14 15function Partyinit(){ 16 for(i=0;i<4;i++){ 17 party[i].partyid = i; 18 partystetas[i]={ 19 maxHP:party[i].Date.Hp, 20 Hp:party[i].Date.Hp, 21 maxpow:party[i].Date.Pow*5, 22 Pow:party[i].Date.Pow, 23 maxDef:party[i].Date.Deff*5, 24 def:party[i].Date.Deff, 25 specialgage:0 26 }; 27 memberView[i]= { 28 hpvar:document.getElementById("HPbox_member"+(i+1)), 29 combcount:document.getElementById("Comb_member"+(i+1)), 30 iconimg:document.getElementById("membericonimg"+(i+1)), 31 Hp:document.getElementById("member"+(i+1)+"_stetas") 32 }; 33 } 34} 35 36function getPartyMemberActionSkill(num){ 37 if(partystetas[num].Hp > 0){//生存中だけ呼び出し 38 party[num].Date.Atkfunction(party[num].AttackDate.Atk); 39 } 40} 41 42function getPartyMemberSapportSkill(num){ 43 party[num].Date.Sapportfunction(party[num].SapportDate.Sap); 44} 45 46function getPartyMemberDamageSkill(num){ 47 party[num].Date.Dam(); 48} 49 50function PartyStetasCheck(i){ 51 if(partystetas[i].Hp <= 0){ 52 party[i].Date.motionsprite=party[i].Date.deadSprite; 53 54 $("#member"+(i+1)+"-icon").addClass("deth"); 55 56 $("#member"+(i+1)+"_stetas").css('color', 'Red'); 57 $("#HPbox_member"+(i+1)).removeClass("alive"); 58 $("#HPbox_member"+(i+1)).addClass("dead"); 59 60 $("#member"+(i+1)+"-icon").removeClass("partymembers-icon"); 61 partystetas[i].Hp++; 62 /*蘇生処理*/ 63 if(partystetas[i].Hp > 0){ 64 65 partystetas[i].Hp = partystetas[i].maxHP/2; 66 $("#member"+(i+1)+"-icon").addClass("partymembers-icon"); 67 $("#member"+(i+1)+"-icon").removeClass("deth"); 68 69 $("#HPbox_member"+(i+1)).addClass("alive"); 70 $("#HPbox_member"+(i+1)).removeClass("dead"); 71 72 } 73 if(Math.abs(partystetas[i].Hp) <= partystetas[i].maxHP){ 74 memberView[i].iconimg.style.opacity=1-(-partystetas[i].Hp/partystetas[i].maxHP); 75 memberView[i].hpvar.style.width = (-partystetas[i].Hp/partystetas[i].maxHP)*100 +"%"; 76 } 77 }else{ 78 if(party[i].Date.motionsprite === party[i].Date.deadSprite){ 79 party[i].Date.motionsprite = party[i].Date.waitSprite; 80 } 81 if($("#HPbox_member"+(i+1)).hasClass("dead")){ 82 $("#HPbox_member"+(i+1)).removeClass("dead"); 83 $("#HPbox_member"+(i+1)).addClass("alive"); 84 }if( $("#member"+(i+1)+"-icon").hasClass("deth")){ 85 $("#member"+(i+1)+"-icon").addClass("partymembers-icon"); 86 $("#member"+(i+1)+"-icon").removeClass("deth"); 87 } 88 89 $("#member"+(i+1)+"_stetas").css('color', 'Black'); 90 memberView[i].hpvar.style.width = (partystetas[i].Hp/partystetas[i].maxHP)*100 +"%"; 91 } 92 if(partystetas[i].Hp > partystetas[i].maxHP)partystetas[i].Hp = partystetas[i].maxHP; 93} 94 95function Party_Update(){ 96 if(GameStage !== "GameOver"){ 97 for(i=0;i<4;i++){ 98 getPartyMemberSapportSkill(i);//Supportを毎時間呼び出す 99 PartyStetasCheck(i); 100 memberView[i].Hp.innerHTML=partystetas[i].Hp; 101 } 102 //全員の状態を調べる 103 for(i=0;i<4;i++){ 104 if(partystetas[i].Hp > 0){ 105 break; 106 } 107 }if(i===4) GameStage="GameOver"; 108}} 109 110 111function Party_Draw(){ 112 for(i=0;i<4;i++){//パーティメンバー描画 113 Characterdtaw(140+markerdistance,45+i*20,party[i].Date.motionsprite);//パーティー 114 } 115} 116

この時、Atk:function()の中で書いている『characters["主人公"]』の部分を変数にして書きたいです。

###やりたいこと
partyidをどのように記述して親オブジェクトから参照したらいいのかわかりません。partyidは他のオブジェクトも共通して持つプロパティであり、一々プロパティ名を指定し自身を参照するのはおかしい気がします。親オブジェクトの持つプロパティを取得するための代表的な記述や別の構造などあれば教えていただきたいです。よろしくお願いします。

###試したこと
this.partyとするとunderfindeで取得できませんでした。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2018/11/11 12:34

再現確認を行いたいので、実際にこのオブジェクトを利用している場面、処理を例示いただけますか?
mijinko889

2018/11/12 10:43

主にキャラクターのステータス部分を使っているスクリプトを追加しました。よろしくお願いします。
mijinko889

2018/11/12 15:03

悩んでいた部分が本題とかけ離れそうなので一旦解決にしました。たくさんの知識をいただけて勉強になりました!キャラデータのポインタのみを管理する配列を別に作り、それをオブジェクトのselfに渡したりする関数をつくって動きそうです。具体的な構造の練り直しに繋がった方をBAにさせていただきました。回答ありがとうございます(;o;)
think49

2018/11/12 15:36

"具体的な構造の練り直しに繋がった方をBAに" そういう切り捨てられ方で質問を閉められるとは思っていませんでした。解決の為に必要な「方法」は具体的に書いてるつもりなんですけどね。
mijinko889

2018/11/12 15:59

本文の情報だけで様々な考え方を教えていただけたのは嬉しかったです。具体的な方法を実際に組み込むように考えた時に自分として考えやすかったものを検討しようと考えたんです。今回の質問回で活かし方がイマイチ分からなかったものも今後使用できるように勉強しようとも思っています。本題に対する個人の捉え方の違いや技術力の違いだと捉えていただきたいです。提示していただいたコードももちろん見ました。端的に言えば、自分が頭弱すぎて複雑なコードや話をまだ理解できなかったということです。BAを選ぶ基準も個人の感性によるかと思います。
guest

回答2

0

オブジェクトの親子

JavaScriptのオブジェクトには「親子」の概念がありません。
つまり、言語仕様の機能を使って親オブジェクトを参照する事は出来ません。

おそらく、DOM APIの parentNode プロパティを意識されているのだと思いますが、あれは初期化時に親ノードを設定する事で機能しています。
要素ノードBを要素ノードAの配下に appendChild する時、「appendChild が要素ノードBの parentNode プロパティ値を要素ノードAに書き換える」のです。

従って、appendChild と同じようにすれば、「親オブジェクトを参照する parent プロパティ」を作ることは可能です。

  • parent プロパティを初期化する汎用のオブジェクト挿入関数 appendObject() を定義する
  • createElement で生成した要素ノードが tagName を持つのと同じように、createCharacter() で生成したキャラクターが name プロパティを持つように作る

疑似 DOM API

以前、作ったものがイメージに近いかもしれません(parentNode を使えます)。

関数 Atk の場所

本題ではありませんが、Atk() の場所が気になります。
現在のコードでは、次のように呼び出しますが、

JavaScript

1characters['主人公'].AttackDate.Atk();

攻撃の主体は「主人公」なので、

JavaScript

1characters['主人公'].Atk();

にするのが自然に見えます。
(※主人公のスタンド能力でスタンド AttackDate が攻撃しているのなら、それでいいですが)

オブジェクト初期化子 {}

変数 characters をオブジェクト初期化子 {} で初期化し、プロパティ名で「キャラクター名」を指定していますが、その場合はキャラクター名に __proto__ が使用出来ません。
任意の名前を持てるようにするには、new Map や多次元配列などの別の手段に変える必要があります。

Re: mijinko889 さん

投稿2018/11/12 03:58

編集2018/11/12 14:57
think49

総合スコア18156

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mijinko889

2018/11/12 11:07

ありがとうございます!とても勉強になります! データを設定する処理を別に作って外部で設定するという考え方で合っていますか? new Character()時に親も設定するようにも検討しようと思います!ありがとうございます
think49

2018/11/12 15:24 編集

> データを設定する処理を別に作って外部で設定するという考え方で合っていますか? 新規オブジェクト生成はコンストラクタで処理し、既存オブジェクトへの挿入は Foo.prototype.append() で挿入時に初期化というイメージですね。 1. new CharacterList(iterableList) で初期化 2. CharacterList.prototype.append(new Character) で (new Character).ownerList を初期化 ここでいう new CharacterList は iterable にしておくと、for-of 等の反復処理が容易になります。 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Iteration_protocols
think49

2018/11/12 15:23

> 2. CharacterList.prototype.append(new Character) で (new Character).ownerList を初期化 私の中では new CharacterList と new Character の関係は親子関係ではなく、所有関係にあると思うので、ownerList としています(Node#ownerDocument と同じ)。 親子関係にするなら、new CharacterList と new Character が同じ性質を持ち、同じ parent, children プロパティを持つオブジェクトをプロトタイプチェーン上に持つよう設計してやる必要があります。
guest

0

ベストアンサー

こんにちは。

前後の背景を知らないと、最適なデータ構造がどういうものかはっきり言えませんが、とりあえずご質問に挙げられているコードの部分だけを見て局所的なリファクタをするとして、以下を一案として考えました。(ES6の classは使っていません。)

javascript

1function AttackDate(discription, count, character) { 2 this.discription = discription; 3 this.count = count; 4 this.character = character; 5} 6 7AttackDate.prototype.Atk = function() { 8 const getDamage = partystetas[this.character.partyid].Pow; 9 Damage(standEnemy[this.character.partyid], getDamage); 10}; 11 12function Character(name, partyid) { 13 this.name = name; 14 this.partyid = partyid; 15} 16

すなわち、コンストラクタAttackDate の引数として、character を受け取り、これをプロパティとして保持しておいて、AttackDateオブジェクトのメソッドからCharacterオブジェクトを使いたいときは、 this.character で参照します。

以下は、上記を使用したサンプルです。

ただし、上記のサンプルでは、とりあえず動くようにするため、ご質問に書かれていない以下を追加しています。

  • standEnemy: 長さ20で、要素が "A", "B", "C" のいずれかである配列

  • partystetas: 長さが20で、要素は 0以上9以下の整数であるプロパティ Powを持つオブジェクト

  • Damage(standEnemy, damage): 単純に2つの引数を console に出力する関数

以上、参考になれば幸いです。

投稿2018/11/12 02:34

編集2018/11/12 02:47
jun68ykt

総合スコア9058

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mijinko889

2018/11/12 11:17

なるほど!例を作っていただいてありがとうございます! こちらのAttackDate()に関数引数を設定するならばやはりコールバック処理で呼び出すべきでしょうか? キャラによって処理が違うことがあるのでprototypeでコールバック用の関数も作ろうと考えたのですが…
jun68ykt

2018/11/13 03:05

こんにちは。 > こちらのAttackDate()に関数引数を設定するならばやはりコールバック処理で呼び出すべきでしょうか? > > キャラによって処理が違うことがあるのでprototypeでコールバック用の関数も作ろうと考えたのですが… の件ですが、できましたら、私が回答に挙げたサンプル https://jsfiddle.net/jun68ykt/e29ao7sm/8/ をForkして頂き(一番上のForkというボタンクリック)、それに > AttackDate()に関数引数を 追加して、 > キャラによって処理が違うこと をやろうとしてみたコードを追加したものを作成して 「こういうことがしたくて、こうしてみたが、このあたりがモヤモヤしてます。」 みたいな感じでコメント頂けますと分かりやすいです。 そこまで問題が明確になったら、別途の質問として投稿したほうが他の回答者さんの知恵も借りれるので、 mijinko889さんにとってより解決が早いかもしれません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問