Jump to content

Recommended Posts

Posted (edited)

I am here with another question.

My Entity / Projectile class is down below. I already managed to simulate gravity and decaying my entity after falling onto the ground, however I have no clue on how to use the Motion variables.
Does someone know how Minecraft uses them? I already looked up the arrow class, but didn't really understand the process.

As an example, I want to shoot my entity into a specified direction, starting at fast Speed and then slowing down.

 

package net.zeldadungeons.init.entity.projectile;

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.IProjectile;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.client.event.sound.SoundEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.zeldadungeons.util.Log;

public class EntitySlingshotPellet extends Entity implements IProjectile {

	private Entity shootingEntity;
	private boolean inGround;
	private int ticksInGround;
	private int ticksInAir;
	
	public EntitySlingshotPellet(World worldIn) {
		super(worldIn);
        this.setSize(0.5F, 0.5F);
	}
	
	public EntitySlingshotPellet(World worldIn, double x, double y, double z) {
		this(worldIn);
		this.setPosition(x, y, z);
	}

    public EntitySlingshotPellet(World worldIn, EntityLivingBase shooter)
    {
        this(worldIn, shooter.posX, shooter.posY + (double)shooter.getEyeHeight() - 0.10000000149011612D, shooter.posZ);
        this.shootingEntity = shooter;
    }
    
    public void onUpdate()
    {
    	super.onUpdate();
    	BlockPos blockpos = new BlockPos(this.posX, this.posY, this.posZ);
        IBlockState iblockstate = this.world.getBlockState(blockpos);
        Block block = iblockstate.getBlock();
        if (iblockstate.getMaterial() != Material.AIR)
        {
            AxisAlignedBB axisalignedbb = iblockstate.getCollisionBoundingBox(this.world, blockpos);
            if (axisalignedbb != Block.NULL_AABB && axisalignedbb.offset(blockpos).contains(new Vec3d(this.posX, this.posY, this.posZ)))
            {
                this.inGround = true;
            }
            
        }
        
        if (this.inGround)
        {
            int j = block.getMetaFromState(iblockstate);

            if (!this.world.collidesWithAnyBlock(this.getEntityBoundingBox().grow(0.05D)))
            {
                this.inGround = false;
                this.motionX *= (double)(this.rand.nextFloat() * 0.2F);
                this.motionY *= (double)(this.rand.nextFloat() * 0.2F);
                this.motionZ *= (double)(this.rand.nextFloat() * 0.2F);
                this.ticksInGround = 0;
                this.ticksInAir = 0;
            }
            else
            {
                ++this.ticksInGround;
                this.doBlockCollisions();
            }
        }
        else
        {
        	this.posY = posY - 0.4D;
        	ticksInAir++;
        }
        if (this.ticksInGround >= 10)
        {
            this.setDead();
            this.world.spawnParticle(EnumParticleTypes.BLOCK_CRACK, this.posX, this.posY+0.5D, this.posZ, 1.0D, 0.0D, 1.0D, 10);
        }
        this.setPosition(posX, posY, posZ);
    }
    
    @SideOnly(Side.CLIENT) @Override
    public boolean isInRangeToRenderDist(double distance)
    {
        double d0 = this.getEntityBoundingBox().getAverageEdgeLength() * 10.0D;

        if (Double.isNaN(d0))
        {
            d0 = 1.0D;
        }

        d0 = d0 * 64.0D * getRenderDistanceWeight();
        return distance < d0 * d0;
    }

	
	@Override
	public void setThrowableHeading(double x, double y, double z, float velocity, float inaccuracy) {
		
	}

	@Override
	protected void entityInit() {
		
	}

	@Override
	protected void readEntityFromNBT(NBTTagCompound compound) {
		
	}

	@Override
	protected void writeEntityToNBT(NBTTagCompound compound) {
		
	}

}

 

Edited by ArmamentHaki
Posted

Position is position.

Motion is velocity, the first derivative of position.

  • Like 1

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted

It doesn't show, it is. Motion is used to modify position. 

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted

Ok so what I planned to do is get rotationYaw and rotation Pitch from the EntityPlayer that shoots my projectile, just like EntityArrow does. However, I dont understand the calculations that are then used by Minecraft. My plan was to always make the projectile move 0.5 Blocks every tick but in every possible direction. The problem is that motionX and motionY already define how fast it goes, so depending on how the player is rotated, the projectile will go faster or slower. I had an idea on how to solve this: motionX*motionX + motionY*motionY would have to be 0.25, basically the sentence of pythagoras. But how can I relate my roationPitch and my rotationYaw to motion? Using sinus may work.. Also, is MathHelper.sqrt the function that gets the root of a value? I am not that good with english mathematical expressions

Posted
  On 11/28/2017 at 7:45 PM, ArmamentHaki said:

but in every possible direction

Expand  

That makes no sense.

  On 11/28/2017 at 7:45 PM, ArmamentHaki said:

I had an idea on how to solve this: motionX*motionX + motionY*motionY

Expand  

This does not help you.

  On 11/28/2017 at 7:45 PM, ArmamentHaki said:

But how can I relate my roationPitch and my rotationYaw to motion? Using sinus may work

Expand  

This is correct.

Rotation is an angle, motion is a direction.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted
  On 11/28/2017 at 7:53 PM, Draco18s said:

That makes no sense.

This does not help you.

This is correct.

Rotation is an angle, motion is a direction.

Expand  

By every possible direction, I meant that the projectile acts like an arrow that can be shot in every direction and acts the same. And if I used motionX*motionX+motionY*motionY = 0.25 it should be useful as it would show that the actual way which is taken by the Entity is 0.5 Blocks long, wouldn't it?

Posted
  On 11/28/2017 at 8:16 PM, ArmamentHaki said:

if I used motionX*motionX+motionY*motionY = 0.25 it should be useful as it would show that the actual way which is taken by the Entity is 0.5 Blocks long

Expand  

motionX*motionX+motionY*motionY = 0.25 is a circle:

http://www.wolframalpha.com/input/?i=x*x+%2B+y*y+%3D+0.25

That is, there are infinitely many values of motionX and motionY that satisfy that equation.

Sure, it tells you that the speed that the entity is taking, but that's not useful here.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted (edited)
  On 11/28/2017 at 9:42 PM, Draco18s said:

motionX*motionX+motionY*motionY = 0.25 is a circle:

http://www.wolframalpha.com/input/?i=x*x+%2B+y*y+%3D+0.25

That is, there are infinitely many values of motionX and motionY that satisfy that equation.

Sure, it tells you that the speed that the entity is taking, but that's not useful here.

Expand  

Thanks for the Explanation.

I have now found a working way to shoot my projectile in a direction.

However, when I do this, the Position is only updated around every ten blocks which makes it look like it is teleporting.

It only updates the Position every 1 or 2 seconds, and when it does, the entity is already gone.

I tried it with smaller velocity, but that just has the same effect only that it doesn't teleport as far.

Here is my class:

package net.zeldadungeons.init.entity.projectile;

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.IProjectile;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.client.event.sound.SoundEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.zeldadungeons.util.Log;

public class EntitySlingshotPellet extends Entity implements IProjectile {

	private Entity shootingEntity;
	private boolean inGround;
	private int ticksInGround;
	private int ticksInAir;
	
	
	public EntitySlingshotPellet(World worldIn) {
		super(worldIn);
        this.setSize(0.5F, 0.5F);
        
	}
	
	public EntitySlingshotPellet(World worldIn, double x, double y, double z) {
		this(worldIn);
		this.setPosition(x, y, z);
		
	}

    public EntitySlingshotPellet(World worldIn, EntityLivingBase shooter)
    {
        this(worldIn, shooter.posX, shooter.posY + (double)shooter.getEyeHeight() - 0.10000000149011612D, shooter.posZ);
        this.shootingEntity = shooter;
        //throws Entity towards a direction
        this.setAim(shooter, shooter.rotationPitch, shooter.rotationYaw, 1F, 1F, 0);
    }
    
    public void setAim(Entity shooter, float pitch, float yaw, float p_184547_4_, float velocity, float inaccuracy)
    {
    	//yaw and pitch are converted into motion values
        float f = -MathHelper.sin(yaw * 0.017453292F) * MathHelper.cos(pitch * 0.017453292F);
        float f1 = -MathHelper.sin(pitch * 0.017453292F);
        float f2 = MathHelper.cos(yaw * 0.017453292F) * MathHelper.cos(pitch * 0.017453292F);
        this.setThrowableHeading((double)f, (double)f1, (double)f2, velocity, inaccuracy);
        this.motionX += shooter.motionX;
        this.motionZ += shooter.motionZ;
        if (!shooter.onGround)
        {
            this.motionY += shooter.motionY;
        }
        Log.getLogger().info("setAim " + f + " " + f1 + " " + f2);
    }
    
    public void onUpdate()
    {
    	
    	super.onUpdate();
    	
    	//test whether the Entity is touching the Ground
    	BlockPos blockpos = new BlockPos(this.posX, this.posY, this.posZ);
        IBlockState iblockstate = this.world.getBlockState(blockpos);
        Block block = iblockstate.getBlock();
        if (iblockstate.getMaterial() != Material.AIR)
        {
            AxisAlignedBB axisalignedbb = iblockstate.getCollisionBoundingBox(this.world, blockpos);
            if (axisalignedbb != Block.NULL_AABB && axisalignedbb.offset(blockpos).contains(new Vec3d(this.posX, this.posY, this.posZ)))
            {
            	//if in Ground, the entity won't move anymore
                this.inGround = true;
                motionX = 0;
                motionY = 0;
                motionZ = 0;
                int j = block.getMetaFromState(iblockstate);

                if (!this.world.collidesWithAnyBlock(this.getEntityBoundingBox().grow(0.05D)))
                {
                    this.inGround = false;
                    this.ticksInGround = 0;
                    this.ticksInAir = 0;
                }
                else
                {
                    ++this.ticksInGround;
                    this.doBlockCollisions();
                }
            }
            
        }
        
        //increases the time in air counter
        if(!this.inGround)
        {
        	ticksInAir++;
        }
        
        //updates entities position, is executed every tick
        posX += motionX;
        posY += motionY;
        posZ += motionZ;
        
        //sets the position
    	this.setPosition(posX, posY, posZ);
        Log.getLogger().info((int)posX + " " + (int)posY + " " + (int)posZ + " " + motionX + " "+ motionY + " " + motionZ);
      
        this.removeEntity();
    }
    
    public void removeEntity()
    {
    	//responsible for removing the entity after it hits the ground
        if (this.ticksInGround >= 10)
        {
            this.setDead();
            this.world.spawnParticle(EnumParticleTypes.BLOCK_CRACK, this.posX, this.posY+0.5D, this.posZ, 1.0D, 0.0D, 1.0D, 10);
        }
    }
    
    @SideOnly(Side.CLIENT) @Override
    public boolean isInRangeToRenderDist(double distance)
    {
        double d0 = this.getEntityBoundingBox().getAverageEdgeLength() * 10.0D;

        if (Double.isNaN(d0))
        {
            d0 = 1.0D;
        }

        d0 = d0 * 64.0D * getRenderDistanceWeight();
        return distance < d0 * d0;
    }

	
	@Override
	public void setThrowableHeading(double x, double y, double z, float velocity, float inaccuracy) {
		float f = MathHelper.sqrt(x*x + y*y + z*z);
		x = x / (double)f;
        y = y / (double)f;
        z = z / (double)f;
        //velocity is added
        this.motionX = x*velocity;
        this.motionY = y*velocity;
        this.motionZ = z*velocity;
        Log.getLogger().info("throw " + f + " " + x + " " + y + " " + z);
	}

	@Override
	protected void entityInit() {
		
	}

	@Override
	protected void readEntityFromNBT(NBTTagCompound compound) {
		
	}

	@Override
	protected void writeEntityToNBT(NBTTagCompound compound) {
		
	}

}

Edit:This seem to be some kind of Client-Server side error as on the server, the position is updated properly, the position updates every 20 ticks on the client

Edited by ArmamentHaki
Posted

That is not a motion problem. That is a entity tracking frequency problem.

Show where you register your entity.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted

My Entity still keeps moving a tiny bit weird when I throw it. I am not sure if ist normal or due to its small Rendering size, but sometimes when I throw it, it moves up or down by a small distance.

 

public void onUpdate() {

		super.onUpdate();
		BlockPos blockpos = new BlockPos(this.posX, this.posY, this.posZ);
		IBlockState iblockstate = this.world.getBlockState(blockpos);
		Block block = iblockstate.getBlock();
		if (iblockstate.getMaterial() != Material.AIR) {
			AxisAlignedBB axisalignedbb = iblockstate.getCollisionBoundingBox(this.world, blockpos);
			if (axisalignedbb != Block.NULL_AABB
					&& axisalignedbb.offset(blockpos).contains(new Vec3d(this.posX, this.posY, this.posZ))) {
				this.inGround = true;
				motionX = 0;
				motionY = 0;
				motionZ = 0;
				int j = block.getMetaFromState(iblockstate);

				if (!this.world.collidesWithAnyBlock(this.getEntityBoundingBox().grow(0.05D))) {
					this.inGround = false;
					this.ticksInGround = 0;
					this.ticksInAir = 0;
				} else {
					++this.ticksInGround;
					this.doBlockCollisions();
				}
			}
		}
		double j = 0;

		if (!this.inGround) {
			ticksInAir++;
		}

		this.posX += this.motionX;
		this.posY += this.motionY;
		this.posZ += this.motionZ;

		float f1 = 0.99F;
		this.motionX *= (double) f1;
		this.motionY *= (double) f1;
		this.motionZ *= (double) f1;
		this.motionY -= 0.05000000074505806D;
		this.updatePos(posX, posY, posZ);
		this.removeEntity();
	}

	public void updatePos(double d1, double d2, double d3) {
		this.setPosition(d1, d2, d3);
	}

	public void removeEntity() {
		if (this.ticksInGround >= 10) {
			this.setDead();
			this.world.spawnParticle(EnumParticleTypes.BLOCK_CRACK, this.posX, this.posY + 0.5D, this.posZ, 1.0D, 0.0D,
					1.0D, 10);
		}
	}

 

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • just rewatched the tutorial and my code is exactly the same as kaupenjoe's.  the item is added into the game but like i said to start it doesnt have a texture or a proper name for whatever reason.
    • yes the name is en_us.json and it is in resources -> assests -> testmod -> lang folders.  i have checked my code and am pretty confident that the code itself is correct.  i even tried loading the project in eclipse and it has the same problems, I think i will just rewatch the whole tutorial and will give an update on the situation.
    • same error, I also tried removing Valkyrian skies as well because I noticed it coming up a lot in the debug log errors
    • Hey man,    i have only been modding Minecraft for a few days but maybe I can help you. First of all make sure to follow every step of Kaupenjoe's tutorial, I found it to been very helpful and complete. The game uses the raw translation key for the item (in your case "item.testmod.alexandrite") if it can't find the correct lang file. Make sure it's name is "en_us.json" and it is saved under "ressources" -> "assets" -> "testmod".
    • whenever I try to get this item to render into the game it appears with the not texture purple and black squares and calls itself by the lang translation file path instead of the name i gave it.   { "item.testmod.alexandrite": "Alexandrite" } this is the lang json file package net.Hurst.testmod.item; import net.Hurst.testmod.TestMod; import net.minecraft.world.item.Item; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegistryObject; public class ModItems { public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, TestMod.MOD_ID); public static final RegistryObject<Item> ALEXANDRITE = ITEMS.register("alexandrite", () -> new Item(new Item.Properties())); public static void register(IEventBus eventBus){ ITEMS.register(eventBus); } } this is my ModItems.java file package net.Hurst.testmod; import com.mojang.logging.LogUtils; import net.Hurst.testmod.item.ModItems; import net.minecraft.world.item.CreativeModeTabs; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.BuildCreativeModeTabContentsEvent; import net.minecraftforge.event.server.ServerStartingEvent; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import org.slf4j.Logger; // The value here should match an entry in the META-INF/mods.toml file @Mod(TestMod.MOD_ID) public class TestMod { public static final String MOD_ID = "testmod"; private static final Logger LOGGER = LogUtils.getLogger(); public TestMod() { IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); modEventBus.addListener(this::commonSetup); ModItems.register(modEventBus); MinecraftForge.EVENT_BUS.register(this); modEventBus.addListener(this::addCreative); ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.SPEC); } private void commonSetup(final FMLCommonSetupEvent event) { } // Add the example block item to the building blocks tab private void addCreative(BuildCreativeModeTabContentsEvent event) { if(event.getTabKey() == CreativeModeTabs.INGREDIENTS){ event.accept(ModItems.ALEXANDRITE); } } // You can use SubscribeEvent and let the Event Bus discover methods to call @SubscribeEvent public void onServerStarting(ServerStartingEvent event) { } // You can use EventBusSubscriber to automatically register all static methods in the class annotated with @SubscribeEvent @Mod.EventBusSubscriber(modid = MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public static class ClientModEvents { @SubscribeEvent public static void onClientSetup(FMLClientSetupEvent event) { } } } this is my TestMod.java file { "parent": "minecraft:item/generated", "textures": { "layer0": "testmod:item/generated" } } this is my model file for the item. I am using intellij 2025.1.2 with fdk 1.21 and java 21 I would appreciate the help.
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.