如何给一个实体加速度(Velocity)

kabuki_


版本信息
IDE:Eclipse
IDE版本:4.12
Forge版本: 14.23.5.2823
Minecraft版本: 1.12
Mapping 文件版本: stable_39

错误情况简述
让玩家朝着一个方向运动,我尝试调用EntityLivingBase#setVelocity()和EntityLivingBase#addVelocity(),但是在此方法调用之后玩家没有任何的反应

(在此之前我也查询过其他论坛的问题,只得到一些匪夷所思的结论,但却没法解决这个问题)

相关代码
ItemClaw.class (物品)

public class ItemClaw extends Item{

	private int progress;
	
	public ItemClaw() {
		super();
		this.maxStackSize = 1;
		setMaxDamage(0);
		setNoRepair();
		setCreativeTab(MRCreativeTab.TOOL);
		this.addPropertyOverride(new ResourceLocation("midgard_reborn", "less"), new IItemPropertyGetter() {
			
			@Override
			public float apply(ItemStack stack, World worldIn, EntityLivingBase entityIn) {
				if(stack.getItem() instanceof ItemClaw)
				{
					return entityIn != null && !isLess(stack) ? 0.0F : 1.0F;
				}
				else
				{
					return 0.0F;
				}
			}
		});
		
	}
	
	@Override
	public ActionResult<ItemStack> onItemRightClick(World worldIn, EntityPlayer playerIn, EnumHand handIn) {
		if(!worldIn.isRemote)
		{
			ItemStack itemstack = playerIn.getHeldItem(handIn);
			if(itemstack != null && itemstack.getItem() instanceof ItemClaw && !isLess(itemstack))
			{
				ProjectileClaw claw = createClaw(playerIn);
				claw.shoot(playerIn, playerIn.rotationPitch, playerIn.rotationYaw, 0.0F, 3.0F, 1.0F);
				setLess(itemstack, true);
				worldIn.spawnEntity(claw);
			}
		}
		return new ActionResult<ItemStack>(EnumActionResult.SUCCESS, playerIn.getHeldItem(handIn));
	}
	
	@Override
	public void onUpdate(ItemStack stack, World worldIn, Entity entityIn, int itemSlot, boolean isSelected) {
		if(!worldIn.isRemote && stack.getItem() instanceof ItemClaw && isLess(stack))
		{
			NBTTagCompound nbt = stack.getTagCompound();
			
			if(nbt == null)
			{
				nbt = new NBTTagCompound();
				nbt.setInteger("progress", 0);
			}
			
			progress = nbt.getInteger("progress");
			if(++progress >= 25)
			{
				this.setLess(stack, false);
				progress = 0;
			}
			nbt.setInteger("progress", progress);
		}
	}
	
	protected ProjectileClaw createClaw(EntityLivingBase throwerIn)
	{
		return new ProjectileClaw(throwerIn.world, throwerIn);
	}
	
	public void setLess(ItemStack itemclaw, boolean value)
	{
		NBTTagCompound nbt = itemclaw.getTagCompound();
		
		if(nbt == null)
		{
			nbt = new NBTTagCompound();
		}

		nbt.setBoolean("less", value);
		itemclaw.setTagCompound(nbt);
	}
	
	public boolean isLess(ItemStack itemclaw)
	{
		NBTTagCompound nbt = itemclaw.getTagCompound();
		
		return nbt == null ? false : nbt.getBoolean("less");
	}
}

ProjectileClaw.class (抛射物)

public class ProjectileClaw extends EntityThrowable{

	private double initmotionX;
	private double initmotionY;
	private double initmotionZ;
	private EntityLivingBase clawthrower;
	
	public ProjectileClaw(World worldIn) {
		super(worldIn);
	}
	
	public ProjectileClaw(World worldIn, double x, double y, double z)
	{
		super(worldIn, x, y, z);
	}
	
	public ProjectileClaw(World worldIn, EntityLivingBase throwerIn) {
		super(worldIn, throwerIn);
		this.clawthrower = throwerIn;
	}

	@Override
	public void onUpdate() {
		EntityLivingBase entitylivingbase = this.getThrower();
		if(entitylivingbase != null && entitylivingbase instanceof EntityPlayer && !entitylivingbase.isEntityAlive())
		{
			this.setDead();
		}
		else
		{
			super.onUpdate();
		}
	}
	
	public static void registerFixesClaw(DataFixer fixer)
	{
		registerFixesThrowable(fixer, "ThrownClaw");
	}

	@Override
	public void shoot(double x, double y, double z, float velocity, float inaccuracy) {
		this.initmotionX = x;
		this.initmotionY = y;
		this.initmotionZ = z;
		super.shoot(x, y, z, velocity, inaccuracy);
	}
	
	@Override
	protected void onImpact(RayTraceResult result) {
		EntityLivingBase entitylivingbase = getThrower();
		if(result.entityHit != null)
		{
			if(result.entityHit == this.clawthrower)
			{
				return;
			}
			result.entityHit.attackEntityFrom(DamageSource.causeThrownDamage(this, entitylivingbase), 1.0F);
		}
		
		if(result.typeOfHit == RayTraceResult.Type.BLOCK)
		{
			if(entitylivingbase != null) 
			{	
				motorize(0.1F);
				this.world.setEntityState(this, (byte) 15);
				this.setDead();
			}	
		}
		
		if(!this.world.isRemote)
		{
			if(this.onGround)
			{
				this.setDead();
			}
		}
	}
	
	protected void motorize(float velocity)
	{
		EntityLivingBase entitylivingbase = getThrower();
		if(entitylivingbase != null)
		{
			double x = entitylivingbase.posX - this.posX;
            double y = entitylivingbase.posY - this.posY;
            double z = entitylivingbase.posZ - this.posZ;
            
	        x = x * (double)velocity;
	        y = y * (double)velocity;
	        z = z * (double)velocity;
	        entitylivingbase.setVelocity(x, y, z);
	        entitylivingbase.sendMessage(new TextComponentString("motorize(x:" + x + " y:" + y + " z:" + z + ")"));//这是测试用的信息,测试时此项是有值且正确的
		}
	}
	
	@Override
	public void writeEntityToNBT(NBTTagCompound compound) {
		super.writeEntityToNBT(compound);
		compound.setDouble("init_motionX", initmotionX);
		compound.setDouble("init_motionY", initmotionY);
		compound.setDouble("init_motionZ", initmotionZ);
	}
	
	@Override
	public void readEntityFromNBT(NBTTagCompound compound) {
		this.initmotionX = compound.getDouble("init_motionX");
		this.initmotionY = compound.getDouble("init_motionY");
		this.initmotionZ = compound.getDouble("init_motionZ");
		super.readEntityFromNBT(compound);
	}
}

加速度的实现在 ProjectileClaw#motorize()ProjectileClaw#onImpact() 调用


FledgeXu


实体应该有个move方法,你需要在实体的tick方法中调用这个move方法,这样就能让实体运动了。
具体你可以查看原版的船的tick方法。
不过我没懂具体什么意思,你想要的是什么动?玩家还是你的实体?


kabuki_


这个实体是玩家
我想要的实现是让玩家根据一个朝向(向量)运动


FledgeXu


你先试试motionXYZ,看看满足不满足你的要求。


FledgeXu


我查了一番资料,发现好像Player的运动是客户端控制的。所以好像没有直接的方法可以控制Player向某个方向走。
可以使用InputUpdateEvent,来模拟这个效果。

You can use the InputUpdateEvent on the client for this purpose.
However note that this is purely client-side (as all player induced motion) and thus you will need server-side verification that the player actually does not move if you want to prevent cheating.
diesieben07




kabuki_


在此前我已经声明过使用了此方法
EntityLivingBase#setVelocity()

    /**
     * Updates the entity motion clientside, called by packets from the server
     */
    @SideOnly(Side.CLIENT)
    public void setVelocity(double x, double y, double z)
    {
        this.motionX = x;
        this.motionY = y;
        this.motionZ = z;
    }

EntityLivingBase#addVelocity()

/**
     * Adds to the current velocity of the entity, and sets {@link #isAirBorne} to true.
     */
    public void addVelocity(double x, double y, double z)
    {
        this.motionX += x;
        this.motionY += y;
        this.motionZ += z;
        this.isAirBorne = true;
    }

然后不知道为什么玩家没有做出任何变化,也许是我的调用的方法不对,或者说我缺少了什么?


kabuki_


这个还没尝试,感谢您热心的帮助,我会耐心的去修改并尝试


FledgeXu


那么motionX应该是不起效的

Player entities do not care about motionXYZ
diesieben07

看我后来发的三个链接中的第一个链接


kabuki_


最后使用了在客户端发送Position数据包来达到线性移动的效果,了解到 handlerInputUpadet仅仅是用来控制每tick玩家的键盘输入
玩家的MovementInput.moveStrafeMovementInput.moveForward 分别是控制玩家前进和横行的,无法做到真正的自定义**“加速度**”,只能用来模拟"移动"

@Mod.EventBusSubscriber(value = Side.CLIENT, modid = MidgardReborn.MODID)
public class HookHandler {
	
	private static double motionX;
	private static double motionY;
	private static double motionZ;
	
	public static boolean isNaN()
	{
		return motionX == 0 && motionY == 0 && motionZ == 0;
	}
	
	public static void setVec(double mX, double mY, double mZ)
	{
		motionX = mX;
		motionY = mY;
		motionZ = mZ;
		
	}
	
	@SideOnly(Side.CLIENT)
	@SubscribeEvent
	public static void handlerInputUpadet(InputUpdateEvent event)
	{
		if(!isNaN())
		{
			event.getMovementInput().forwardKeyDown = false;
			event.getMovementInput().leftKeyDown = false;
			event.getMovementInput().rightKeyDown = false;
			event.getMovementInput().backKeyDown = false;
			
			
			if(event.getEntityPlayer() instanceof EntityPlayerSP)
			{
				EntityPlayerSP sp = (EntityPlayerSP) event.getEntityPlayer();
				sp.lastTickPosX = sp.posX;
				sp.lastTickPosY = sp.posY;
				sp.lastTickPosZ = sp.posZ;
		        
//		        sp.posX += motionX;
//		        sp.posY += motionY;
//		        sp.posZ += motionZ;
		        
		        double x = sp.posX + motionX;
		        double y = sp.posY + motionY;
		        double z = sp.posZ + motionZ;
		        
		        float f1 = 0.8F;
		        float f2 = 0.1F;
		        
		        if(sp.isInWater())
		        {
		        	f1 = 0.6F;
		        }
		        
		        if(!sp.capabilities.isCreativeMode)
				{
					sp.chasingPosY -= f2;
				}
		        
		        sp.setPosition(x, y, z);
		        BlockPos blockpos = new BlockPos(sp.posX, sp.getEntityBoundingBox().minY, sp.posZ);
		        BlockPos blockpos0 = new BlockPos(-1, -1, -1);
		        IBlockState blockstate = sp.world.getBlockState(blockpos);
		        IBlockState blockstate0 = sp.world.getBlockState(blockpos0);
		        
		        if(blockstate.getBlock() == blockstate0.getBlock())
		        {
		        	sp.onGround = false;
		        }
		        
				sp.connection.sendPacket(new CPacketPlayer.Position(x, y, z, sp.onGround));
				motionX *= f1;
				motionZ *= f1;
				motionY *= f1;
				
				if(motionX * motionX + motionY * motionY + motionZ * motionZ <= 0.5D)
				{
					motionX = 0;
					motionY = 0;
					motionZ = 0;
				}
			}
		}
		else
		{
			event.getMovementInput().forwardKeyDown = true;
			event.getMovementInput().leftKeyDown = true;
			event.getMovementInput().rightKeyDown = true;
			event.getMovementInput().backKeyDown = true;
		}
	}
}

system


该主题在最后一个回复创建后7天后自动关闭。不再允许新的回复。