From 82365329424a60e2844d884e85a10b9f6acd5eb1 Mon Sep 17 00:00:00 2001 From: Ouchi <0319saiku@gmail.com> Date: Mon, 24 Nov 2025 18:32:03 +0900 Subject: [PATCH 01/14] =?UTF-8?q?=E3=82=A4=E3=83=B3=E3=82=BF=E3=83=BC?= =?UTF-8?q?=E3=83=95=E3=82=A7=E3=83=BC=E3=82=B9Tips=E8=A8=98=E4=BA=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/content/blog/interface-tips.md | 287 +++++++++++++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 src/content/blog/interface-tips.md diff --git a/src/content/blog/interface-tips.md b/src/content/blog/interface-tips.md new file mode 100644 index 0000000..b9fc7dc --- /dev/null +++ b/src/content/blog/interface-tips.md @@ -0,0 +1,287 @@ +--- +title: ゲーム開発で例えるinterface +pubDate: '2025-11-24' +description: ゲーム開発で例えるinterface +author: Millin +tags: [Tech, C#] +--- + +こんにちは!ゲームエンジニアのMillinです。 + +今回はinterfaceについてゲーム開発での活用例を交えて解説したいと思います。 + +今回、例題のコードはC#で書きますが、たいていの言語で同様の活用ができるかと思います。 + +## インターフェイスとは +特定の関数やプロパティを持つことを明示する型です。 + +以下のように記述し、定義したInterface型の変数から関数やプロパティを呼び出すことができます。 +```cs +interface ITest +{ + int Value { get;} + void Test(); +} + +class Foo : ITest +{ + int value; + public int Value => value; + + public void Test() + { + value = 3; + Console.WriteLine("Hello, World!"); + } +} + +class Program +{ + static void Main(string[] args) + { + ITest test = new Foo(); + //Hello, World!が表示される。 + test.Test(); + //3が表示される。 + Console.WriteLine(test.Value); + } +} +``` + +変数を持つことはできません。(C#ではコンパイルエラーになります。) +```cs +interface ITest +{ + int test; + void Test(); +} +``` + +interfaceに定義された関数やプロパティがinterfaceを適用したクラスにない場合もコンパイルエラーになります。 +```cs +interface ITest +{ + void Test(); +} + +//interfaceで定義されているTest()がない +class Foo : ITest +{ +} +``` + +継承と違い複数のインターフェースをクラスに適用することができます。(C++などの多重継承できる言語は除く) +```cs +interface ITest +{ + void Test(); +} + +interface ITest2 +{ + void Test2(); +} + +class Foo : ITest, ITest2 +{ + public void Test() + { + Console.WriteLine("Hello, World!"); + } + + public void Test2() + { + Console.WriteLine("Hello, World!"); + } +} +``` + +## ゲームでの活用例 +以下のような仕様を想定します。(この段階ではInterfaceは必要ありません) + +- すべてのクラスはObjectを継承する +- キャラクター・弾があり、弾はキャラクターにダメージを与える。 +```cs +class Object +{ +} + +class Character : Object +{ + //体力 + int hp; + + public void Damage() + { + hp--; + } +} + +class Bullet : Object +{ + public void Hit(Character character) + { + character.Damage(); + } +} +``` +シンプルですね。ここで以下の追加仕様があった場合のinterfaceを使用しない場合と使用した場合の違いを比較してみます。 +- 弾で壊せる箱(BreakableBox)・壊せない箱(Box)がある。 +- 箱は持ち運ぶことができる。 + +#### インターフェースを使用しない場合1(Bullet内でキャストして分岐) +```cs +class Object +{ +} + +class Character : Object +{ + //体力 + int hp; + + public void Damage() + { + hp--; + } +} + +class Bullet : Object +{ + public void Hit(Object obj) + { + if(obj is Character character) + { + character.Damage(); + } + else if( obj is BreakableBox breakableBox) + { + breakableBox.Damage(); + } + } +} + +class BoxBase : Object +{ + public void Carry() + { + //運ぶ処理 + } +} + +class Box : BoxBase +{ +} + +class BreakableBox : BoxBase +{ + public void Damage() + { + //壊れる処理 + } +} +``` +Bullet内でのキャラクターとBreakableBoxの二つに依存し、多態性が全く実現できていない状態になります。 + +#### インターフェースを使用しない場合2(ObjectにDamage処理を持たせる) +```cs +class Object +{ + public virtual void Damage() + { + } +} + +class Character : Object +{ + //体力 + int hp; + + public override void Damage() + { + hp--; + } +} + +class Bullet : Object +{ + public void Hit(Object obj) + { + obj.Damage(); + } +} + +class BoxBase : Object +{ + public void Carry() + { + //運ぶ処理 + } +} + +class Box : BoxBase +{ +} + +class BreakableBox : BoxBase +{ + public override void Damage() + { + //壊れる処理 + } +} +``` +特定のサブクラス(BreakableBox や Character)のための処理が基底に書かれるのは継承関係として正しくないです。 + + +#### インターフェースを使用した場合 +```cs +interface IDamageable +{ + void Damage(); +} + +class Object +{ +} + +class Character : Object, IDamageable +{ + //体力 + int hp; + + public void Damage() + { + hp--; + } +} + +class Bullet : Object +{ + public void Hit(IDamageable damageable) + { + damageable.Damage(); + } +} + +class BoxBase : Object +{ + public void Carry() + { + //運ぶ処理 + } +} + +class Box : BoxBase +{ +} + +class BreakableBox : BoxBase, IDamageable +{ + public void Damage() + { + //壊れる処理 + } +} +``` +多態性や継承関係が適切に保たれます! From 6e546fca4324ddcad5ce8bde674e6dc016c27ed7 Mon Sep 17 00:00:00 2001 From: Ouchi <0319saiku@gmail.com> Date: Mon, 24 Nov 2025 18:36:16 +0900 Subject: [PATCH 02/14] =?UTF-8?q?=E4=B8=80=E9=83=A8=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/content/blog/interface-tips.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/blog/interface-tips.md b/src/content/blog/interface-tips.md index b9fc7dc..35c5364 100644 --- a/src/content/blog/interface-tips.md +++ b/src/content/blog/interface-tips.md @@ -181,7 +181,7 @@ class BreakableBox : BoxBase } } ``` -Bullet内でのキャラクターとBreakableBoxの二つに依存し、多態性が全く実現できていない状態になります。 +Bullet内でCharacterとBreakableBoxの二つに依存し、多態性が全く実現できていない状態になります。 #### インターフェースを使用しない場合2(ObjectにDamage処理を持たせる) ```cs From 5a3f2723005f1045188daa1f618829307b228968 Mon Sep 17 00:00:00 2001 From: Naoki_Ito <117070296+naoki-00-ito@users.noreply.github.com> Date: Sun, 30 Nov 2025 00:59:18 +0900 Subject: [PATCH 03/14] =?UTF-8?q?=F0=9F=90=9E=20fix:=20md=20warning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/content/blog/interface-tips.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/content/blog/interface-tips.md b/src/content/blog/interface-tips.md index 35c5364..5bdce90 100644 --- a/src/content/blog/interface-tips.md +++ b/src/content/blog/interface-tips.md @@ -13,14 +13,16 @@ tags: [Tech, C#] 今回、例題のコードはC#で書きますが、たいていの言語で同様の活用ができるかと思います。 ## インターフェイスとは + 特定の関数やプロパティを持つことを明示する型です。 以下のように記述し、定義したInterface型の変数から関数やプロパティを呼び出すことができます。 + ```cs interface ITest { int Value { get;} - void Test(); + void Test(); } class Foo : ITest @@ -49,6 +51,7 @@ class Program ``` 変数を持つことはできません。(C#ではコンパイルエラーになります。) + ```cs interface ITest { @@ -58,6 +61,7 @@ interface ITest ``` interfaceに定義された関数やプロパティがinterfaceを適用したクラスにない場合もコンパイルエラーになります。 + ```cs interface ITest { @@ -71,6 +75,7 @@ class Foo : ITest ``` 継承と違い複数のインターフェースをクラスに適用することができます。(C++などの多重継承できる言語は除く) + ```cs interface ITest { @@ -97,10 +102,12 @@ class Foo : ITest, ITest2 ``` ## ゲームでの活用例 + 以下のような仕様を想定します。(この段階ではInterfaceは必要ありません) - すべてのクラスはObjectを継承する - キャラクター・弾があり、弾はキャラクターにダメージを与える。 + ```cs class Object { @@ -125,11 +132,14 @@ class Bullet : Object } } ``` + シンプルですね。ここで以下の追加仕様があった場合のinterfaceを使用しない場合と使用した場合の違いを比較してみます。 + - 弾で壊せる箱(BreakableBox)・壊せない箱(Box)がある。 - 箱は持ち運ぶことができる。 -#### インターフェースを使用しない場合1(Bullet内でキャストして分岐) +### インターフェースを使用しない場合1(Bullet内でキャストして分岐) + ```cs class Object { @@ -181,9 +191,11 @@ class BreakableBox : BoxBase } } ``` + Bullet内でCharacterとBreakableBoxの二つに依存し、多態性が全く実現できていない状態になります。 -#### インターフェースを使用しない場合2(ObjectにDamage処理を持たせる) +### インターフェースを使用しない場合2(ObjectにDamage処理を持たせる) + ```cs class Object { @@ -231,10 +243,11 @@ class BreakableBox : BoxBase } } ``` + 特定のサブクラス(BreakableBox や Character)のための処理が基底に書かれるのは継承関係として正しくないです。 +### インターフェースを使用した場合 -#### インターフェースを使用した場合 ```cs interface IDamageable { @@ -284,4 +297,5 @@ class BreakableBox : BoxBase, IDamageable } } ``` + 多態性や継承関係が適切に保たれます! From 81de89c69e6f1d1bb3dff374ce3213fd5ea3204c Mon Sep 17 00:00:00 2001 From: Naoki_Ito <117070296+naoki-00-ito@users.noreply.github.com> Date: Sun, 30 Nov 2025 01:07:27 +0900 Subject: [PATCH 04/14] =?UTF-8?q?=F0=9F=90=9E=20fix:=20MemberCard=20height?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MemberCard.astro | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/components/MemberCard.astro b/src/components/MemberCard.astro index c801a2e..4204926 100644 --- a/src/components/MemberCard.astro +++ b/src/components/MemberCard.astro @@ -10,6 +10,7 @@ import { import MemberAvatar from '@/components/MemberAvatar'; import type { Member } from '@/types/Member'; import Icon from './Icon.astro'; +import { cn } from '@/lib/utils'; interface Props { items: Member[]; layout?: 'author'; @@ -21,11 +22,18 @@ const { items, layout } = Astro.props; { items.map(member => ( - - + + {layout === 'author' && 'Author: '} {member.name} @@ -49,7 +57,7 @@ const { items, layout } = Astro.props; )} {member.links && ( - +
    {member.links.map(link => (
  • From 6e2450546cae0124d03f5ed53e61d4c09538ad15 Mon Sep 17 00:00:00 2001 From: Naoki_Ito <117070296+naoki-00-ito@users.noreply.github.com> Date: Sun, 30 Nov 2025 01:16:53 +0900 Subject: [PATCH 05/14] =?UTF-8?q?=F0=9F=A6=84=20refactor:=20ui=20component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/badge.tsx | 1 - src/components/ui/button.tsx | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx index 2eb790a..97056f6 100644 --- a/src/components/ui/badge.tsx +++ b/src/components/ui/badge.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { cva, type VariantProps } from 'class-variance-authority'; import { cn } from '@/lib/utils'; diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index 81e2e6e..710e1c3 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { forwardRef } from 'react'; import { Slot } from '@radix-ui/react-slot'; import { cva, type VariantProps } from 'class-variance-authority'; @@ -39,7 +39,7 @@ export interface ButtonProps asChild?: boolean; } -const Button = React.forwardRef( +const Button = forwardRef( ({ className, variant, size, asChild = false, ...props }, ref) => { const Comp = asChild ? Slot : 'button'; return ( From 96814278de8c469ead77bbaafcb9b4cebe5586ec Mon Sep 17 00:00:00 2001 From: Naoki_Ito <117070296+naoki-00-ito@users.noreply.github.com> Date: Sun, 30 Nov 2025 01:21:33 +0900 Subject: [PATCH 06/14] =?UTF-8?q?=F0=9F=90=9E=20fix:=20ui=20component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/badge.tsx | 3 ++- src/components/ui/button.tsx | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx index 97056f6..e95ff88 100644 --- a/src/components/ui/badge.tsx +++ b/src/components/ui/badge.tsx @@ -1,6 +1,7 @@ import { cva, type VariantProps } from 'class-variance-authority'; import { cn } from '@/lib/utils'; +import type { HTMLAttributes } from 'react'; const badgeVariants = cva( 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', @@ -23,7 +24,7 @@ const badgeVariants = cva( ); export interface BadgeProps - extends React.HTMLAttributes, + extends HTMLAttributes, VariantProps {} function Badge({ className, variant, ...props }: BadgeProps) { diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index 710e1c3..89bcf89 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -1,4 +1,4 @@ -import { forwardRef } from 'react'; +import { forwardRef, type ButtonHTMLAttributes } from 'react'; import { Slot } from '@radix-ui/react-slot'; import { cva, type VariantProps } from 'class-variance-authority'; @@ -34,7 +34,7 @@ const buttonVariants = cva( ); export interface ButtonProps - extends React.ButtonHTMLAttributes, + extends ButtonHTMLAttributes, VariantProps { asChild?: boolean; } From f2637590d8b4e919eae26ab82a3451e1a7c09a27 Mon Sep 17 00:00:00 2001 From: Naoki_Ito <117070296+naoki-00-ito@users.noreply.github.com> Date: Sun, 30 Nov 2025 01:28:16 +0900 Subject: [PATCH 07/14] =?UTF-8?q?=F0=9F=90=9E=20fix:=20update=20prettierig?= =?UTF-8?q?nore=20and=20fix=20customData=20format=20in=20rss.xml.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .prettierignore | 3 ++- src/pages/[author]/rss.xml.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.prettierignore b/.prettierignore index 3f005b5..d1828aa 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,5 +1,6 @@ pnpm-lock.yaml -src/styles/globals.css +src/components/ui src/content/ +src/styles/globals.css public/ *.md diff --git a/src/pages/[author]/rss.xml.js b/src/pages/[author]/rss.xml.js index e37b41c..8300acf 100644 --- a/src/pages/[author]/rss.xml.js +++ b/src/pages/[author]/rss.xml.js @@ -28,6 +28,6 @@ export async function GET(context) { customData: blog.data.customData, link: `/blog/${blog.slug}/`, })), - customData: `ja-jp`, + customData: 'ja-jp', }); } From 5dfed157e718260abbebd9aec46f97335fe071fe Mon Sep 17 00:00:00 2001 From: Naoki <117070296+naoki-00-ito@users.noreply.github.com> Date: Sun, 30 Nov 2025 01:35:38 +0900 Subject: [PATCH 08/14] Update src/content/blog/interface-tips.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/content/blog/interface-tips.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/blog/interface-tips.md b/src/content/blog/interface-tips.md index 5bdce90..729ff39 100644 --- a/src/content/blog/interface-tips.md +++ b/src/content/blog/interface-tips.md @@ -21,7 +21,7 @@ tags: [Tech, C#] ```cs interface ITest { - int Value { get;} + int Value { get; } void Test(); } From 3f8e279106084b8857d441b65517ebdb0335a3c1 Mon Sep 17 00:00:00 2001 From: Naoki <117070296+naoki-00-ito@users.noreply.github.com> Date: Sun, 30 Nov 2025 01:35:50 +0900 Subject: [PATCH 09/14] Update src/content/blog/interface-tips.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/content/blog/interface-tips.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/blog/interface-tips.md b/src/content/blog/interface-tips.md index 729ff39..90367d7 100644 --- a/src/content/blog/interface-tips.md +++ b/src/content/blog/interface-tips.md @@ -65,7 +65,7 @@ interfaceに定義された関数やプロパティがinterfaceを適用した ```cs interface ITest { - void Test(); + void Test(); } //interfaceで定義されているTest()がない From d18669b27c6cdcd10b5fe5ecc2ffb06403bdf599 Mon Sep 17 00:00:00 2001 From: Naoki <117070296+naoki-00-ito@users.noreply.github.com> Date: Sun, 30 Nov 2025 01:36:35 +0900 Subject: [PATCH 10/14] Update src/components/MemberCard.astro Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/components/MemberCard.astro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MemberCard.astro b/src/components/MemberCard.astro index 4204926..2b2a781 100644 --- a/src/components/MemberCard.astro +++ b/src/components/MemberCard.astro @@ -32,7 +32,7 @@ const { items, layout } = Astro.props; > Date: Sun, 30 Nov 2025 01:36:53 +0900 Subject: [PATCH 11/14] Update src/components/ui/badge.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/components/ui/badge.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx index e95ff88..ede85e8 100644 --- a/src/components/ui/badge.tsx +++ b/src/components/ui/badge.tsx @@ -1,7 +1,7 @@ import { cva, type VariantProps } from 'class-variance-authority'; +import type { HTMLAttributes } from 'react'; import { cn } from '@/lib/utils'; -import type { HTMLAttributes } from 'react'; const badgeVariants = cva( 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', From 747664496ea07239515e31626f81e212d53680bb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 16:37:54 +0000 Subject: [PATCH 12/14] Initial plan From 4be8e046a1aab26265ea2b8ac1173edba49cbd07 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 16:39:52 +0000 Subject: [PATCH 13/14] Fix inconsistent indentation in code block (3 spaces -> 4 spaces) Co-authored-by: naoki-00-ito <117070296+naoki-00-ito@users.noreply.github.com> --- src/content/blog/interface-tips.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/blog/interface-tips.md b/src/content/blog/interface-tips.md index 90367d7..ee9378e 100644 --- a/src/content/blog/interface-tips.md +++ b/src/content/blog/interface-tips.md @@ -79,7 +79,7 @@ class Foo : ITest ```cs interface ITest { - void Test(); + void Test(); } interface ITest2 From 68e5dfff029f3c0f43c4e80ad5911e3c91c232b3 Mon Sep 17 00:00:00 2001 From: Naoki_Ito <117070296+naoki-00-ito@users.noreply.github.com> Date: Sun, 30 Nov 2025 01:40:34 +0900 Subject: [PATCH 14/14] =?UTF-8?q?=F0=9F=90=9E=20fix:=20formatting=20in=20M?= =?UTF-8?q?emberCard.astro=20for=20better=20readability?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MemberCard.astro | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/MemberCard.astro b/src/components/MemberCard.astro index 2b2a781..a702aa7 100644 --- a/src/components/MemberCard.astro +++ b/src/components/MemberCard.astro @@ -32,7 +32,8 @@ const { items, layout } = Astro.props; >