Solved Move Armorstands in pairs

Discussion in 'Plugin Development' started by I Al Istannen, Dec 22, 2015.

Thread Status:
Not open for further replies.
  1. Offline

    I Al Istannen

    Hello,

    I wanted to create a Snitch in Bukkit. To make it look at least a little bit nice I decided to use Armorstands to display the parts (wings and body). This worked quite well but another problem appeared. While it looked ok with smaller velocities, it quickly became uglier at higher. Right now I modify the velocity of every armorstand involved at the same time and teleports them if they get too far apart.
    I would really appriacte the help to fix this problem.

    Code:
    public class Snitch extends BaseEntity<ArmorStand> {
      
       private float fleeingSpeed;
       private double rightArmCounter;
       private ArmorStand leftArm, rightArm;
      
       /**
        * The default constructor for Snitch
        *
        * @param speed The speed at which the entity should move
        * @param world The world the entity is in
        * @param name The name of the Snitch
        * @param spawnLocation The Spawn Location of the Snitch
        */
       public Snitch(float speed, World world, String name, Location spawnLocation) {
         super(speed, world, name, spawnLocation);
         fleeingSpeed = speed + (speed / 100) * 20;
       }
    
       @Override
       public void doMove() {
         if(entity == null || !entity.isValid()) {
           return;
         }
         for(Entity e : entity.getNearbyEntities(5, 5, 5)) {
           if(e.getType() == EntityType.PLAYER) {
             Vector v = entity.getLocation().toVector().subtract(e.getLocation().toVector());
             moveInDirection(v, arena, fleeingSpeed);
             return;
           }
         }
        
         if(ThreadLocalRandom.current().nextInt(100) <= 10) {
           moveRandom(arena);
         }
         else {
           moveInDirection(entity.getVelocity().setY(createRandomFloat()), arena, speed);   // they have gravity, don't let them fall down
         }
       }
      
       private void moveRandom(Arena arena) {
         float x = createRandomFloat();
         float y = createRandomFloat();
         float z = createRandomFloat();
        
         moveInDirection(new Vector(x, y, z), arena, speed);
       }
      
       private void moveRightArm() {
         EulerAngle angle = new EulerAngle(Math.abs(rightArmCounter), 1.62, 0.3316);
         rightArm.setRightArmPose(angle);
            
         if(rightArmCounter > 0.4) {
           rightArmCounter = -0.4;
         }
        
         rightArmCounter+= 0.1;
       }
      
       private void moveLeftArm() {
         EulerAngle angle = new EulerAngle(Math.abs(rightArmCounter), 1.62, 0.3316);
         leftArm.setRightArmPose(angle);
       }
      
       private float createRandomFloat() {
         return ThreadLocalRandom.current().nextBoolean() ? -ThreadLocalRandom.current().nextFloat() : ThreadLocalRandom.current().nextFloat();
       }
      
       private void moveInDirection(Vector dir, Arena arena, float speed) {
         entity.setVelocity(getCorrected(dir, arena, speed));
        
         if (entity.getLocation().distanceSquared(leftArm.getLocation()) >= 2.25
             || entity.getLocation().distanceSquared(rightArm.getLocation()) >= 2.25) {
          
           rightArm.teleport(entity.getLocation());
           Location loc = entity.getLocation();
           loc.setDirection(entity.getLocation().getDirection().multiply(-1));     // other wing, has to be rotated by 180 degree
           leftArm.teleport(loc);
         }
        
         leftArm.setVelocity(getCorrected(dir, arena, speed));
         moveLeftArm();
         rightArm.setVelocity(getCorrected(dir, arena, speed));
         moveRightArm();
       }
      
       private Vector getCorrected(Vector dir, Arena arena, float speed) {
         Vector endVec = dir.normalize().multiply(speed);
         if(!arena.getBounds().isInside(entity.getLocation().toVector().add(endVec))) {
           return getVectorAwayFromEdge(arena);
         }
         return endVec;
       }
      
       private Vector getVectorAwayFromEdge(Arena arena) {
         return arena.getBounds().getRandomPointInside().subtract(entity.getLocation().toVector()).normalize().multiply(speed);  
       }
    
       @Override
       public void kill() {
         if(entity == null) return;
         entity.remove();
         leftArm.remove();
         rightArm.remove();
         entity = null;
       }
      
       @Override
       public void spawn() {
         entity = (ArmorStand) world.spawnEntity(spawnLocation, EntityType.ARMOR_STAND);
         entity.setCustomName(name);
         entity.setCustomNameVisible(true);
         entity.setHelmet(new ItemStack(Material.GOLD_BLOCK));
         entity.setSmall(true);
         entity.setVisible(false);
        
         Location loc = entity.getLocation();
         // rotate by 180 degrees to make it appear on the right side
         loc.setDirection(entity.getLocation().getDirection().multiply(-1));
         leftArm = (ArmorStand) world.spawnEntity(loc, EntityType.ARMOR_STAND);
         leftArm.setArms(true);
         leftArm.setItemInHand(new ItemStack(Material.GOLD_NUGGET));
         leftArm.setVisible(false);
        
         rightArm = (ArmorStand) world.spawnEntity(spawnLocation, EntityType.ARMOR_STAND);
         rightArm.setArms(true);
         rightArm.setItemInHand(new ItemStack(Material.GOLD_NUGGET));
         rightArm.setVisible(false);
       }
      
       @Override
       public void reactToDamagyByOtherEntity(EntityDamageByEntityEvent e) {
         System.out.println("Snitch.reactToDamagyByOtherEntity()");
         super.reactToDamagyByOtherEntity(e);
        
         if(e.getDamager() instanceof Player && e.getEntity() == entity) {
           PlayingPlayer player = arena.getPlayingPlayerByUUID(e.getDamager().getUniqueId());
           if(player == null) {
             return;
           }
          
           if(player.getPlayingClass() == PlayingClass.SEEKER) {
             GameInfoMessages.sendSnitchCatchedMessage(arena, player);
             arena.endGame();
           }
         }
       }
    
    }
    
     

    Attached Files:

  2. I think you have a spelling error: reactToDamagyByOtherEntity ?
    Does it look okay if you don't animate the two arms? I personally like to get the core movement done before animating the parts of it. You probably shouldn't have to teleport them at all, eh?
     
  3. Offline

    I Al Istannen

    @BreezerFly Oh yes. I have the spelling error in the superclass though, which means it is sadly not the problem but thanks for pointing it out :). While you are certainly right to do the core movement at first, not moving the armorstands' arms didn't help.
    To the teleporting, they sadly don't share the exact same hitboxes. This means, that a part can be blocked by a block, while the others still move. This leads to a total destruction of the poor snitch.
     
    Last edited: Dec 22, 2015
  4. For curiousity. Why are you using rightArm for the left wing? I guess it's so you can use the same logic?
    What does it look like in a slow velocity, when it's working?

    Can we use a single armorstand?
    ArmorStand#setLeftArmPose
    ArmorStand#setRightArmPose
     
  5. Offline

    I Al Istannen

    @BreezerFly An Armorstand can only have an item in it's right hand as far as i Know. That's why I use two. Luckily that changed in 1.9 :D. Yes, it is to be able to use the same logic. It looks like the first gif I posted if it stands still and doesnt change much when I move it. You can see in the first gif i will attach how it workd, but alos how it gets dislocated in the second gif. That is why I tried to teleport them together again.
     

    Attached Files:

  6. Oooh, duh. That's right I suppose... I've never worked with armorstands :3
    Is it too taxing to simply teleport the "child" armor stands onto the parent armor stand each tick? Rather than setting their velocity independently?
     
  7. Offline

    I Al Istannen

    @BreezerFly You may laugh, but this was the first thing I tried. It looked even more grotesque. The teleportation wasnt really done reliable and it just glitched out at every velocity.

    I tried it again and it seems to work better. Don't ask me why though. Still has some kind of delay, but that may be the limitations of minecraft. My thoughts were that it would be smoother if the other armorstands get the same movement updates as the "parent" at the same time. Doesn't seem to be possible though. I may try some combination of the techniques although there are some issues (NoGravity is requiered for the teleportation, but cancelles every velocity change (logically))

    Anyway, thanks for your help!
     

    Attached Files:

  8. Offline

    Zombie_Striker

    @I Al Istannen
    Has your problem been solved? If so, mark this thread as solved.
     
  9. Offline

    I Al Istannen

    @Zombie_Striker Im not quite sure :D The lag you can still see is probably related to minecraft and not my code, so I guess I will mark this as solved. Thanks for the reminder :)
     
Thread Status:
Not open for further replies.

Share This Page