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
53 minutes ago, Draco18s said:

Position is position.

Motion is velocity, the first derivative of position.

All right. So basically, the xmotion shows how fast an entity moves into direction x. If a Position was calculated by x*x, the motion would be 2x?

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
7 minutes ago, ArmamentHaki said:

but in every possible direction

That makes no sense.

7 minutes ago, ArmamentHaki said:

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

This does not help you.

7 minutes ago, ArmamentHaki said:

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

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
17 minutes ago, Draco18s said:

That makes no sense.

This does not help you.

This is correct.

Rotation is an angle, motion is a direction.

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
1 hour ago, 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

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)
27 minutes ago, 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.

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 (edited)
6 hours ago, Draco18s said:

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

Show where you register your entity.

I was only tracking every 20 ticks.

It does work now.

Edited by ArmamentHaki
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



×
×
  • Create New...

Important Information

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