0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

マイクラでDTMっぽいことをやる試み

Last updated at Posted at 2025-12-03

概要

  • マイクラ×DTMの夢の可能性
  • クリスマスソングを作成してみる
  • 基本的に25音に制限されているので表現できる曲は限られてくると感じる

コード

MusicBoxBlockの作成

MusicBoxBlock.java
package com.example.examplemod.music_box;

import com.example.examplemod.ExampleMod;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Material;
import net.minecraft.world.phys.BlockHitResult;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class MusicBoxBlock extends BaseEntityBlock implements EntityBlock {
    public MusicBoxBlock(){
        super(BlockBehaviour.Properties.of(Material.STONE));
    }

    @Override
    public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, BlockHitResult pHit) {
        if(!pLevel.isClientSide){
            BlockEntity blockEntity=pLevel.getBlockEntity(pPos);
            if(blockEntity instanceof MusicBoxBlockEntity musicBoxBlockEntity){
                musicBoxBlockEntity.setPlaying(!musicBoxBlockEntity.getPlaying());
                if(musicBoxBlockEntity.getPlaying())
                {
                    pPlayer.displayClientMessage(new TextComponent("再生します"),true);
                }
                else
                {
                    pPlayer.displayClientMessage(new TextComponent("停止します"),true);
                }
                //変更をクライアントに同期
                musicBoxBlockEntity.setChanged();
                pLevel.sendBlockUpdated(pPos,pState,pState,3);
            }
        }
        return InteractionResult.SUCCESS;
    }
    @Override
    public @NotNull RenderShape getRenderShape(@NotNull BlockState pState) {
        return RenderShape.MODEL;
    }

    @Nullable
    @Override
    public BlockEntity newBlockEntity(BlockPos pPos, BlockState pState) {
        return new MusicBoxBlockEntity(pPos,pState);
    }

    @Nullable
    @Override
    public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level pLevel, BlockState pState, BlockEntityType<T> pBlockEntityType) {
        return createTickerHelper(pBlockEntityType, ExampleMod.MUSIC_BOX_BLOCK_ENTITY,MusicBoxBlockEntity::tick);
    }
}

MusicBoxBlockEntityの作成

MusicBoxBlockEntity.java
package com.example.examplemod.music_box;

import com.example.examplemod.ExampleMod;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.NotNull;

public class MusicBoxBlockEntity extends BlockEntity {
    private int songId;
    private boolean isPlaying=false;
    private int songProgressTick=0;

    public MusicBoxBlockEntity(BlockPos pPos, BlockState pState){
        super(ExampleMod.MUSIC_BOX_BLOCK_ENTITY,pPos,pState);
    }

    @Override
    protected void saveAdditional(@NotNull CompoundTag pTag) {
        super.saveAdditional(pTag);
        pTag.putInt("SongId",this.songId);
        pTag.putInt("SongProgress",this.songProgressTick);
        pTag.putBoolean("IsPlaying",this.isPlaying);
    }

    @Override
    public void load(@NotNull CompoundTag pTag) {
        super.load(pTag);
        this.songId=pTag.getInt("SongId");
        this.songProgressTick=pTag.getInt("SongProgress");
        this.isPlaying=pTag.getBoolean("IsPlaying");
    }
    @Override
    public @NotNull CompoundTag getUpdateTag() {
        CompoundTag tag=new CompoundTag();
        saveAdditional(tag);//現在のデータをNBTに保存
        return tag;
    }

    @Override
    public void handleUpdateTag(CompoundTag tag) {
        load(tag);//受け取ったNBTでデータを読み込み
    }

    public static void tick(Level level, BlockPos pos, BlockState state, MusicBoxBlockEntity blockEntity) {
        if (!blockEntity.isPlaying || level.isClientSide) {
            return;
        }

        SongData currentSong=MusicLibrary.SONGS.get(blockEntity.songId);
        if(currentSong==null){
            blockEntity.isPlaying=false;
            return;
        }

        for(NoteData note: currentSong.notes){
            if(note.startTick==blockEntity.songProgressTick){
                float pitch=(float) Math.pow(2.0D, (double) (note.pitch-12)/12.0D);
                level.playSound(null,pos,SoundEvents.NOTE_BLOCK_HARP,SoundSource.RECORDS,1.0F,pitch);
                if(level instanceof ServerLevel serverLevel){
                    serverLevel.sendParticles(ParticleTypes.NOTE,
                            pos.getX()+0.5D,
                            pos.getY()+1.2D,
                            pos.getZ()+0.5D,
                            1,
                            (double) note.pitch/24.0D,
                            0.0D,
                            0.0D,
                            1.0D
                            );
                }
            }
        }

        blockEntity.songProgressTick++;
    }
    public int getSongId(){
        return this.songId;
    }
    public boolean getPlaying(){
        return this.isPlaying;
    }
    public void setSongId(int id){
        this.songId=id;
    }
    public void setPlaying(boolean is){
        this.isPlaying=is;
        if(this.isPlaying){
            this.songProgressTick=0;
        }
    }
}

NoteDataクラスの作成

音階といつ鳴らすかのデータが入ります。

NoteData.java
package com.example.examplemod.music_box;

public class NoteData {
    public final int pitch;
    public final int startTick;
    public NoteData(int pitch, int startTick){
        this.pitch=pitch;
        this.startTick=startTick;
    }
}

SongDataクラスの作成

NoteDataクラスのリストと、全体の再生時間を保持します。

SongData.java
package com.example.examplemod.music_box;

import java.util.List;

public class SongData {
    public final List<NoteData> notes;
    public final int totalTicks;

    public SongData(List<NoteData> notes, int totalTicks){
        this.notes=notes;
        this.totalTicks=totalTicks;
    }
}

MusicLibraryクラスの作成

今後複数曲に対応したいのでIntegerとSongDataをMapで保持するクラスを作成します。

MusicLibrary.java
package com.example.examplemod.music_box;

import java.util.List;
import java.util.Map;

public class MusicLibrary {
    //曲IDと楽譜データのマップ
    public static final Map<Integer, SongData> SONGS=Map.of(
            0, new SongData(
                    List.of(
                            new NoteData(13, 0),
                            new NoteData(18, 10),new NoteData(6,10),
                            new NoteData(18, 20),
                            new NoteData(20, 25),
                            new NoteData(18, 30), new NoteData(6, 30),
                            new NoteData(17, 35),
                            new NoteData(15, 40), new NoteData(11, 40),
                            new NoteData(15, 50),
                            new NoteData(15, 60), new NoteData(11, 60),
                            new NoteData(20, 70), new NoteData(8, 70),
                            new NoteData(20, 80),
                            new NoteData(22,85),
                            new NoteData(20,90), new NoteData(13,90),
                            new NoteData(18,95),
                            new NoteData(17, 100), new NoteData(13, 100),
                            new NoteData(13, 110),
                            new NoteData(13, 120), new NoteData(13, 120),
                            new NoteData(22, 130), new NoteData(10, 130),
                            new NoteData(22, 140),
                            new NoteData(23, 145),
                            new NoteData(22,150), new NoteData(10,150),
                            new NoteData(20,155),
                            new NoteData(18, 160), new NoteData(15,160),
                            new NoteData(15, 170),
                            new NoteData(13, 180), new NoteData(15,180),
                            new NoteData(13,185),
                            new NoteData(15,190), new NoteData(11,190),
                            new NoteData(20,200),
                            new NoteData(17,210), new NoteData(13,210),
                            new NoteData(18,220), new NoteData(6,220),
                            new NoteData(13,240), new NoteData(6,240),
                            new NoteData(18, 250), new NoteData(6,250),
                            new NoteData(18,260),
                            new NoteData(18, 270), new NoteData(18, 270),
                            new NoteData(17, 280), new NoteData(13,280),
                            new NoteData(17, 300), new NoteData(13, 300),
                            new NoteData(18, 310), new NoteData(11,310),
                            new NoteData(17,320),
                            new NoteData(15,330), new NoteData(11,330),
                            new NoteData(13,340), new NoteData(13,340),
                            new NoteData(10,360), new NoteData(13,360),
                            new NoteData(11,370), new NoteData(11,370),
                            new NoteData(10,380),
                            new NoteData(8,390), new NoteData(11,390),
                            new NoteData(13,400), new NoteData(10,400),
                            new NoteData(13,410),
                            new NoteData(13,420), new NoteData(10,420),
                            new NoteData(13,425),
                            new NoteData(15,430), new NoteData(11,430),
                            new NoteData(20, 440), new NoteData(13, 440),
                            new NoteData(17,450), new NoteData(8,450),
                            new NoteData(18,460), new NoteData(6,460)
                    ),
                    480 // この曲の総Tick数 (16小節 * 30tick/小節)
            ),
            1, new SongData(
                    List.of(
                            new NoteData(13,0),
                            new NoteData(13,10),
                            new NoteData(15,20),
                            new NoteData(15,30)
                    ),
                    40
            )
    );
}

とりあえず完成!!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?