(Solved) Loot-Chest

Discussion in 'Programming' started by sunyx, May 16, 2018.

  1. Hello! Can anyone tell me how to create the animation (From the Crate at 00:55) from the video?
    Thank You :D
     
  2. I coded the Holos already. I only need the circular animation
     
  3. The math that you are probably looking for is explained here
     
  4. I alreadly tried it for over 8 hours so it would be nice if anyone can write the code for me because 8 hours are enough xd.
     
  5. What did you try/post your current code...
     
  6. Code (Text):
    public Location getLocationAroundCircle(Location center, double radius, double angleInRadian) {
            double x = center.getX() + radius * Math.cos(angleInRadian);
            double z = center.getZ() + radius * Math.sin(angleInRadian);
            double y = center.getY();

            Location loc = new Location(center.getWorld(), x, y, z);
            Vector difference = center.toVector().clone().subtract(loc.toVector()); // this sets the returned location's
                                                                                    // direction toward the center of the
                                                                                    // circle
            loc.setDirection(difference);

            return loc;
        }

     
    public void open(Player p, Treasure treasure) {

            final Location lo = p.getLocation().clone();

            List<TreasureHologram> holos = new ArrayList<>();

            int points = 9; // amount of points to be generated
            for (int i = 0; i < 370; i += 370 / points) {

                double angle = (i * Math.PI / 180);
                double x = 4 * Math.cos(angle);
                double z = 4 * Math.sin(angle);
                Location loc = lo.clone().add(x, 0, z);
                TreasureHologram th = new TreasureHologram(
                        this.treasureItems.get(new Random().nextInt(treasureItems.size())));

                th.spawn(loc);
                holos.add(th);

            }

            TreasureHologram winHologram = new TreasureHologram();
            winHologram.spawnText(lo.clone().add(4 * Math.cos(82 * Math.PI / 180), 0.3, 4 * Math.sin(82 * Math.PI / 180)));

            holos.get(0).getItem().remove();
            holos.get(0).getRarityText().setCustomNameVisible(false);
            holos.get(0).getArmorstand().setCustomNameVisible(false);

            new BukkitRunnable() {

                int angle = 10;

                @Override
                public void run() {

                    for (int i = 0; i < holos.size(); i++) holos.get(i).teleport(holos.get((i + 1 != holos.size() ? i + 1 : 0)).getLocation(), angle);
                    p.playSound(p.getLocation(), Sound.CLICK, 1F, 1F);
                    angle--;
                   
                    if (angle == 0) {

                        cancel();
                        TreasureItem ti = holos.get(2).getTreasureItem();
                        holos.forEach(a -> {
                            a.remove();
                        });
                        winHologram.remove();

                        winItem(p, ti, treasure);

                    }

                }

            }.runTaskTimer(RayNight.getInstance(), 10, 10);

        }
     
    TreasureHologram is just a holo
     
    #6 sunyx, May 16, 2018
    Last edited: May 17, 2018
  7. It is not smooth and i want to add the items one by one not all Armorstands instant
     
  8. You shouldn't make new Random instance in that loop(creating it is heavy), make it outside or use ThreadLocalRandom
    And for the "smooth animation" you need to teleport armor stands every tick, if you don't want them to appear instantly then don't spawn them instantly
    Also you should probably change the way you are doing things, for example make a loop(bukkit timer) like this:
    Code (Text):
    -check if the loop should stop instantly(for example if player disconnected/died, etc..)

    -check if you should spawn new armorstand

    -teleport spawned armorstands to their location on circle around player/location

    -check if the loop should/is slowing down and decrease "-increase circle offset"(and pick a winner when it slows down and stop the loop)

    -increase circle offset

    -check if the loop is running longer than X seconds and set slowing down to true if it is
    and you would have player interact event handler somewhere to tell the loop to start slowing down

    I don't want to spoon feed you code but if you want i can post the code i wrote so you can use it as a reference(copy-pasting won't help you if you want to write more code in future)
     
    #8 Mareckoo01, May 17, 2018
    Last edited: May 17, 2018
  9. Well i tried it again today but i messed up :(Can you please give your code so i can understand the circular rotations better? I know Copy paste is bad. But im not copying anything. Ill look through your code and try to understand. Thank you :)
     
  10. It works roughly the same way as i wrote in my post.
    To understand the math take a look at the link i posted before(check his other tutorials too).
    The only thing that this is missing is what i would call "pernament circle offset", you will need to calculate it from chest location (so that it looks like items appear from chest)
    And i would recommed you to use your player wrapper instead of List and Map to store information

    Code (Text):
        private List<UUID> playersDoingTheThing = new ArrayList<>();
        private Map<UUID, Boolean> cancelTheThing = new HashMap<>(); // true = start slowing down and give reward, false = stop instantly and don't give reward
        public BukkitTask doTheThing(Player pl, int numberOfArmorstands, double speed, double radius, Location winLocation){
            if(playersDoingTheThing.contains(pl.getUniqueId())) return null; // already running for this player
            playersDoingTheThing.add(pl.getUniqueId());
            return new BukkitRunnable() {
                List<ArmorStand> armorstands = new ArrayList<>();
                Player p = pl;
                int numOfAS = numberOfArmorstands,
                    ran = 0,
                    endAtRun = -1;
                double PI_2 = Math.PI*2,
                        rad = radius,
                        spd = speed,
                        currentOffset = 0,
                        asOffset = PI_2/numOfAS;
                Location winLoc = winLocation;
               
                @Override
                public void run() {
                    if(!p.isOnline() || p.isDead() || (cancelTheThing.containsKey(p.getUniqueId()) && !cancelTheThing.get(p.getUniqueId()))){ // check if task should stop (instantly)
                        cancel();
                        armorstands.forEach(a -> a.remove());
                        armorstands.clear();
                        playersDoingTheThing.remove(p.getUniqueId());
                        cancelTheThing.remove(p.getUniqueId());
                        return;
                    }
                    Location pLoc = p.getLocation().clone();
                    if(armorstands.size() < numOfAS){ // check if we should spawn new armor stands
                        if(Math.toRadians(currentOffset) >= asOffset*armorstands.size()){
                            ArmorStand as = (ArmorStand) pLoc.getWorld().spawnEntity(pLoc.clone().add(0, -10, 0), EntityType.ARMOR_STAND);
                            as.setBasePlate(false);
                            as.setArms(true);
                            as.setGravity(false);
                            as.setInvulnerable(true);
                            as.setRightArmPose(new EulerAngle(Math.toRadians(355), Math.toRadians(40), Math.toRadians(10)));
                            as.getEquipment().setItemInMainHand(new ItemStack(Material.values()[ThreadLocalRandom.current().nextInt(Material.values().length)])); //add your item
                            as.setCustomName("ArmorStand #" + (armorstands.size()+1));
                            as.setCustomNameVisible(true);
                            as.setVisible(false);
                            armorstands.add(as);
                            return; // need to wait 1 tick after spawning new armor stand otherwise it will desync client side
                        }
                    }
                   
                    int asNum = 0;
                    double cO = Math.toRadians(currentOffset%360d);
                    for(double d = 0; d<PI_2; d+=PI_2/numOfAS){ // rotate armorstands
                        if(asNum >= armorstands.size()) break;
                        double a = d+cO,
                                cos = Math.cos(a),
                                sin = Math.sin(a);
                        ArmorStand as = armorstands.get(asNum++);
                        Location l = pLoc.clone().add(cos*rad, 0, -sin*rad);
                        l.setDirection(pLoc.toVector().subtract(l.toVector()).normalize());
                        as.teleport(l);
                    }
                    double m = 1d;
                    if(armorstands.size()==numOfAS && cancelTheThing.getOrDefault(p.getUniqueId(), false)){
                        if(endAtRun == -1) endAtRun = ran + 20*3 + ThreadLocalRandom.current().nextInt(20*5); // end time = 3 to 8 seconds from now
                        if(ran >= endAtRun){ // if we reached end time
                            ArmorStand closest = null;
                            double closestDistance = Double.MAX_VALUE;
                            for(ArmorStand as : armorstands){
                                double distance = as.getLocation().distance(winLoc); // this is a bit heavy, consider making different method of picking winning armorstand
                                if(distance < closestDistance){
                                    closestDistance = distance;
                                    closest = as;
                                }
                            }
                            if(closest != null){
                                ItemStack is = closest.getItemInHand();
                                if(is.hasItemMeta() && is.getItemMeta().hasDisplayName()){
                                    p.sendMessage("You got " + is.getItemMeta().getDisplayName());
                                } else {
                                    p.sendMessage("You got " + is.getType().name());
                                }
                                p.getInventory().addItem(is);
                               
                            }
                            cancel();
                            armorstands.forEach(as -> as.remove());
                            armorstands.clear();
                            playersDoingTheThing.remove(p.getUniqueId());
                            cancelTheThing.remove(p.getUniqueId());
                            return; // finished
                        }
                        int remaining = endAtRun-ran;
                        m = .1+remaining/20d/10d; // 0.1 to 0.9 modifier
                    }
                   
                    currentOffset+=spd*m;
                    ran++;
                    if(ran > 20*20 && !cancelTheThing.containsKey(p.getUniqueId())){ // limit to 20 seconds
                        cancelTheThing.put(p.getUniqueId(), true);
                    }
                }
            }.runTaskTimer(this, 0, 1);
        }
       
        public Map<UUID, Boolean> getCancelTheThing(){
            return cancelTheThing;
        }
       
        public List<UUID> getPlayersDoingTheThing(){
            return playersDoingTheThing;
        }
       
        @EventHandler
        public void onClick(PlayerInteractEvent e){
            if(e.getAction() == Action.PHYSICAL) return;
            Player p = e.getPlayer();
            if(getPlayersDoingTheThing().contains(p.getUniqueId()) && !getCancelTheThing().containsKey(p.getUniqueId())){
                getCancelTheThing().put(p.getUniqueId(), true);
            }
        }
    Code (Text):
    public class TestCommand implements CommandExecutor {
        private SCT instance;
       
        public Test(SCT instance){
            this.instance = instance;
        }

        @Override
        public boolean onCommand(CommandSender arg0, Command arg1, String arg2, String[] arg3) {
            if(!(arg0 instanceof Player)) return false;
            Player p = (Player) arg0;
            instance.doTheThing(p, 8, 11.25, 4d, p.getLocation().clone().add(p.getLocation().getDirection().multiply(3)));
            p.sendMessage("Started!");
            return true;
        }

    }
    And add few other improvements..
     
  11. Thank you! It will take some time to understand everything but i have something where i can learn from :D I really appreciate your help.
    :3 Solved
     

Share This Page