Non-physique similaire utilisé pour exprimer le baseball sur Minecraft et mise en œuvre dans Spigot (capture de balle / Conseils)

Autres articles

Lié Lancer et frapper

Capture

Il n'y a pas beaucoup de difficulté à mettre en œuvre la partie attrape-balle. Pour le moment, tout ce que vous avez à faire est de ramasser le ProjectileHitEvent '' et de passer au jugement lorsque la balle frappe le joueur. Dans le cas de SnowballGame, si vous avez un objet appelé "saisir" en main libre, vous pouvez attraper la balle sans condition. Au moment de la capture, la balle de l'entité est retirée et la balle est ajoutée à l'inventaire du joueur attrapeur. Étonnamment, cela nécessite à lui seul quelques conseils pour attraper le ballon, par exemple lorsque le ballon et le joueur n'appellent pas ProjectileHitEvent '' quand il s'agit d'une balle au sol bas ou quand c'est juste le moment de rebondir sur le sol. Il y a une scène qui devient. (Lorsqu'un voltigeur charge avec un tiret vers un goro qui rampe sur le sol, il y a de bonnes chances qu'il prenne du retard. Le réel est réel, et pour certaines personnes, c'était une spécification qui évoque un traumatisme.)

Tâche

Ce n'est pas aussi gênant que de l'appeler un problème, mais il y a encore des parties insatisfaisantes dans la reproduction du baseball avec cette spécification. Premièrement, il n'y a pas d'erreurs de rattrapage (erreurs) telles que frapper une balle. À ce propos, il est possible de faire en sorte qu'une erreur se produise avec une probabilité aléatoire lorsqu'un événement est appelé, mais cela peut alors sembler déraisonnable car le joueur ne peut pas contrôler la probabilité d'occurrence d'erreur. Je veux le concevoir de manière à ce que la compétence affecte dans une certaine mesure la qualité du jeu.

L'autre est que la difficulté d'attraper la balle elle-même est trop élevée. Dans Minecraft, la zone de frappe du joueur est essentiellement dans un état où la main est abaissée, donc avec cette spécification, le concept «atteindre une balle pour attraper» n'existe pas, pour ainsi dire, pour tous les coups. Il devra "s'enrouler autour de l'avant" et attraper la balle. Par conséquent, il est très courant qu'un goro rapide passe à travers le champ intérieur, et les types de balles frappées qui peuvent être attrapées sont très limités jusqu'à ce qu'il devienne possible de deviner comment la balle frappée volera au moment de frapper avec une certaine expérience de jeu. Cela avait été fait. De plus, l'effet de "ne pas pouvoir étendre le bras" était plus prononcé dans l'attrape à la mouche dans la défense de champ extérieur, et il y avait pas mal de cas où l'attrape à la mouche échouait même lorsque la balle était presque au point de largage.

Solution

C'est une histoire très simple, et j'ai rendu possible d'attraper la balle en faisant un clic droit dans une certaine zone près de la balle. La détection qu'un clic droit a été effectué est `PlayerInteractEvent``` et` `ʻevent.getAction ()` est Action.RIGHT_CLICK_AIR ou `RIGHT_CLICK_BLOCK```. Vous pouvez le faire en déterminant, alors assurez-vous que le joueur a une prise dans la main gauche et rien dans la main principale (pour éviter un dysfonctionnement). De plus, en acquérant la distance entre le ballon et le joueur dans cette plage fixe, il peut être utilisé comme un indice indiquant une "mauvaise posture" au moment de la capture du ballon. Autrement dit, plus cette valeur est élevée, plus il y a de chances qu'une "erreur" se produise. Les habiletés de jeu apparaissent dans le fait d'essayer d'attraper le ballon au moment où la distance entre vous et le ballon est la plus proche (ou d'essayer de supprimer le ballon à un moment plus tôt tout en incorporant la possibilité d'erreurs pour faire sortir le frappeur) Il y a de la place, et le jugement de frappe est simplement un peu élargi, donc même si le mouvement est un peu lent, la plage qui peut être sortie s'est élargie. Dans SnowballGame, lorsqu'un clic droit est effectué, si la balle est dans la case 3 * 4 * 3 des yeux du joueur, la balle est jugée attrapée, et à partir de Math.Random * 8 '' Si la distance à la balle est petite, la balle est attrapée avec succès, et si elle est plus grande que cela, c'est une erreur.

tryCatch


//tryCatch(player, player.getEyeLocation(), new Vector(3,4,3), 8)Appelé sous la forme de
//La valeur de retour est booléenne, en pensant qu'il existe une méthode d'utilisation qui est plus pratique si vous connaissez le succès ou l'échec de la capture de la balle.
public static boolean tryCatch(Player player, Location from, Vector range, double rate){
		Collection <Entity> nearByEntities = player.getWorld().getNearbyEntities(from, range.getX(), range.getY(), range.getZ());
		Inventory inventory = player.getInventory();
		for(Entity ball : nearByEntities){
			if(ball.getType() == EntityType.SNOWBALL && Util.isBall(ball)){
				if(Math.random() * rate > from.distance(ball.getLocation())){
					ball.remove();
					ItemStack itemBall = Util.getItemBall();
                    //S'il y a de la place dans l'inventaire, déposez-le dans l'inventaire, sinon déposez-le en tant qu'objet
					if(inventory.containsAtLeast(itemBall,1) || inventory.firstEmpty() != -1){
						player.getInventory().addItem(itemBall);
                        return true;
					}else{
						ball.getWorld().dropItem(ball.getLocation(), itemBall);
					}
				}else{
					ball.setGravity(true);
                    //La balle que vous jouez ajoute un vecteur aléatoire tout en multipliant aléatoirement la vitesse
					ball.setVelocity(ball.getVelocity().multiply(Math.random()).add(Vector.getRandom().multiply(0.3)));
				}
			}
		}
		return false;
}

Tips Voici quelques-unes des idées que j'ai acquises lors du développement de Snowball Game et des plugins associés qui pourraient m'aider à créer d'autres plugins sportifs (ou non).

Implémentation non aléatoire et non rotative

Les balles d'articulation dans le baseball et les balles non rotatives, appelées flotteurs ou balles non rotatives dans d'autres sports, sont extrêmement sensibles à l'environnement environnant tel que l'atmosphère, et leur force est que la trajectoire devient irrégulière. C'est un type de balle. Je ne sais pas comment on le traite dans d'autres sports, mais au baseball, les knuckle balls sont des "boules magiques modernes" pour lesquelles il n'y a toujours pas de stratégie définitive, et si elles sont lancées avec une grande précision. Il n'est pas exagéré de dire que c'est un morceau de romance, comme un ancien voltigeur devenant un lanceur de première classe et étant le meilleur lanceur du monde à l'apogée si un coup de poing d'environ 130 kg est lancé. Parce que c'est une balle changeante pleine de tels rêves, je veux vraiment l'implémenter dans le plug-in de baseball, mais malheureusement, le principe introduit dans Throwing Edition est knuckle. Les changements sont indescriptibles.

Le changement de jointure ne peut pas être expliqué par la force de levage due à l'effet Magnus utilisé ici, et la majeure partie du changement est causée par "la balle de baseball n'est pas une balle". (Pour dire la vérité, même s'il s'agit d'une vraie sphère, des changements irréguliers se produisent, mais je vais omettre l'explication ici.) Par conséquent, la direction et la quantité de changements ne peuvent pas être décrites par une formule simple. Calcul de l'orbite nécessite une simulation assez élaborée, Cela ne semble pas être quelque chose qu'un amateur peut atteindre.

En d'autres termes, il faut renoncer dès le départ pour reproduire fermement la trajectoire d'une bille non rotative. En plus de cela, le problème est de savoir à quel point la trajectoire de l'image est proche de l'articulation réelle.

Lors de la mise en œuvre de modifications irrégulières, la chose la plus simple à trouver est d'ajouter un vecteur aléatoire à chaque tick à la balle. Cela peut certainement entraîner des changements irréguliers, est facile à mettre en œuvre et a fière allure en tant que représentation d'articulation. Cependant, lorsque vous lancez réellement la "boule d'articulation" que vous avez implémentée de cette manière, vous remarquerez immédiatement une sensation d'inconfort. Une balle articulée en réalité est une balle qui montre un «balancement» environ 1 à 3 fois du lanceur au gant du receveur, et il est complètement imprévisible dans quelle direction elle finira par tourner. On peut dire qu'un changement de trajectoire, comme un virage lent vers le frappeur et une chute brutale, est une condition nécessaire pour l'expression d'un coup de poing.

D'un autre côté, cette boule d'articulation «vecteur aléatoire» fait des changements imprévisibles, mais elle provoque trop de «secousses». Fondamentalement, il progresse en changeant dans différentes directions, mais au final, il annule souvent les changements dans les directions opposées et arrive à une position où il est facile de prévoir. Dans le pire des cas, la balle peut devenir une balle droite qui tremble juste dans les airs, et la difficulté initiale de frapper la jointure ne peut pas être exprimée avec cela. javaw_20180604_233815F.gif Définissez random à 0,02 comme "norme de l'ampleur du changement aléatoire" et utilisez le vecteur obtenu par Vector.getRandom (). Subtract (Vector.getRandom ()). Multiply (2 * random) `` comme une boule. Celui ajouté est le gif ci-dessus. Vous pouvez certainement voir le mouvement d'un côté à l'autre, mais ils s'annulent et le résultat est la même balle qui change à peine.

Afin d'exprimer la ressemblance de la phalange, il doit être sous une forme qui change dans une direction dans une certaine mesure tout en changeant de direction plusieurs fois. Cependant, la méthode de définition de certains modèles de changement et de branchement au hasard ... semble un peu redondante.

Dans SnowballGame, la méthode consistant à "partir d'un point aléatoire sur la courbe sin et avancer d'une taille aléatoire" est répétée à chaque tick pour chacun des x, y, z et le vecteur obtenu est ajouté à la balle. Cela a été exprimé en utilisant.

Le changement d'orbite consiste essentiellement à savoir si x, y et z sont respectivement + ○○ ou - △△. Et le contenu du changement qui est recherché maintenant est que "ce sera + ou-continuellement pendant une période irrégulière, et alors-ou + commencera à être inversé à un moment irrégulier." Ensuite, pour exprimer cela, il suffit d'avoir une fonction qui bascule entre + et-avec une certaine période et une certaine plage de valeurs à mesure que la valeur de l'argument augmente. Si vous ajoutez une valeur fractionnaire (aléatoire) de ce cycle à chaque argument de graduation, il doit se comporter comme prévu. Parmi les fonctions avec ces propriétés, la fonction la plus simple que je connaisse était sin (ou cos). Il va et vient en continu dans la plage de 1 à -1 à intervalles réguliers. Il ne devient pas soudainement une grande valeur ou ne devient pas infini. (Pour autant que je sache) Bien sûr, il est utilisé simplement parce qu'il est "pratique", et il n'y a aucune base pour justifier l'utilisation de ce péché. (En parlant de cela, les coutures de la balle peuvent ressembler à une courbe sinusoïdale.) C'est une manière similaire non physique et sale que certains scientifiques peuvent avoir de l'urticaire, mais c'est gagné de cette façon. La jointure qui a été faite est devenue une jointure décente. javaw_20180605_000615F.gif La différence est évidente par rapport à la «formule de vecteur aléatoire» ci-dessus. Cette fois, j'ai eu du mal à le lancer dans la zone de frappe, mais la quantité de changement était telle que le match avec le frappeur était établi. Le code pour implémenter cette articulation est le suivant.

Knuckle


import org.bukkit.Particle;
import org.bukkit.entity.Projectile;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
//Cette classe utilise le même Runnable que la sphère changeante lors de l'implémentation réelle.
public class BallMovingTask extends BukkitRunnable {
    private Projectile ball;
    private double random = 0;
    private double x,y,z;

	public BallMovingTask(Projectile ball, double random) {
        this.ball = ball;
        this.random = random;
        if(random != 0){
        	this.x = Math.random() * 2 * Math.PI;
        	this.y = Math.random() * 2 * Math.PI;
        	this.z = Math.random() * 2 * Math.PI;
        }
	}
    @Override
    public void run() {
    	if(ball.isDead()){
    		this.cancel();
    	}
    	Vector velocity = ball.getVelocity();
    	if(random != 0){
            //Environ 15 d'un monticule au frappeur-Il est considéré comme 20 ticks, donc chaque tick 0~0.3 si vous continuez 1~Devrait "secouer" 3 fois
        	this.x += Math.random() * 0.3;
        	this.y += Math.random() * 0.3;
        	this.z += Math.random() * 0.3;
        	Vector toAdd = new Vector(Math.sin(x), Math.sin(y), Math.sin(z));
        	toAdd.multiply(random);
        	velocity.add(toAdd);
    	}
    	ball.setVelocity(velocity);
    }

}

Si vous permettez de définir le hasard standard de cette quantité de changement dans la configuration, il sera ajusté de manière à ce qu'il soit facile à gérer pour chaque joueur.

Jauge unique utilisant Boss Bar

En ce qui concerne la frappe du baseball, il y avait des caractéristiques telles que "arrêter le pied" et "la précision de l'angle et de la direction n'est pas si importante", il était donc possible de l'exprimer en utilisant un arc qui avait à l'origine une jauge. , Lors de l'expression d'autres sports, il est possible que l'arc ne soit pas pratique. Par exemple, lors de l'expression du football, des réglages de force de type jauge sont utilisés dans des jeux célèbres pour la partie tir, mais l'exprimer avec un arc n'est pas une très bonne méthode. Il y a un problème en ce que la vitesse de déplacement de l'arc diminue considérablement en tirant, et la vitesse à laquelle la jauge s'accumule est un peu trop lente pour l'expression du tir. Par conséquent, dans un tel cas, une interface utilisateur de type jauge avec un degré de liberté plus élevé est requise.

Par conséquent, Bossbar peut être utilisé comme un moyen efficace. À l'origine, il n'était utilisé que pour afficher la force physique restante de boss tels que Ender Dragon et Wither, mais comme vous pouvez le voir dans la documentation, il ne nécessite en fait aucune entité pour appeler le constructeur. Au contraire, afin de refléter la force physique de l'entité, il est nécessaire d'écrire seul le processus d'augmentation / diminution, et inversement, il peut être utilisé librement en plus d'afficher la force physique. La valeur à afficher peut être directement réécrite entre 0-1 en utilisant `` Bossbar.setProgress (double) '', donc si vous écrivez Runnable et réécrivez chaque valeur de graduation, elle augmentera ou diminuera à n'importe quelle vitesse. Vous pouvez créer une jauge à faire. Bien sûr, il n'y a pas d'effets secondaires dérangeants comme lors de l'utilisation d'un arc.

Il existe un plug-in de jeu de golf appelé OutOfBounds qui fonctionne sur Snowball Game en tant que plug-in prérequis pour mon propre plug-in. Une jauge de résistance utilisant Boss Bar a été adoptée pour le montage. Un film de démonstration (gif) est publié sur la page Spigot, veuillez donc le vérifier si vous le souhaitez.

En dehors des limites

La spécification est que la partie frappée du jeu de boule de neige est utilisée pour juger si le swing a frappé la balle et comment elle a frappé.

Pour exprimer cela, l'écouteur d'événements

PlayerInteract


if(e.getAction() == Action.LEFT_CLICK_AIR || e.getAction() == Action.LEFT_CLICK_BLOCK){
	e.setCancelled(true);
	if(player.hasMetadata("taskID") && player.hasMetadata("bar")){
		int isRight = 1;
		if(player.getMainHand() == MainHand.LEFT){
			isRight = -1;
		}
		Location loc = player.getLocation();
		loc.setYaw(loc.getYaw() - 90 * isRight);
		//Direction gauche de la ligne de visée pour simplifier(Droitier)En supposant un swing dans la direction de 90 degrés
		Vector swing = loc.getDirection().setY(0).normalize();
		BossBar powerBar = (BossBar)player.getMetadata("bar").get(0).value();
		//Sur le prolongement de la ligne de visée 1.En supposant que la position de 8 m est la position où passe la tête du club
		Location start = player.getEyeLocation().add(player.getEyeLocation().getDirection().normalize().multiply(1.8));
		//Fonction de jugement du jeu de boule de neige
		// tryHit(Battre,Position des fesses,Frapper le jugement xyz,Comment l'arc est tiré,Élan de chauve-souris,Coefficient de répulsion de balle)
		SnowballGameAPI.tryHit(player, start, new Vector(1.2,1.2,1.2), (float)powerBar.getProgress(), 1.3, swing, 1);
			Bukkit.getScheduler().cancelTask(player.getMetadata("taskID").get(0).asInt());
			powerBar.removeAll();
			powerBar.setProgress(0.001);
			player.removeMetadata("taskID", plugin);
			return;
		}
		BossBar powerBar = null;
		//Il ne semblait pas souhaitable de créer un BossBar à chaque fois que vous jouez, donc le premier swing de chaque joueur
		//Celui créé une seule fois est donné sous forme de métadonnées et réutilisé.
		if(player.hasMetadata("bar")){
			powerBar = (BossBar)player.getMetadata("bar").get(0).value();
			powerBar.setColor(BarColor.GREEN);
		}else{
			powerBar = Bukkit.getServer().createBossBar("Power", BarColor.GREEN, BarStyle.SOLID);
		}
		powerBar.setProgress(0);
		powerBar.addPlayer(player);
		BukkitTask task = new PowerBarTask(powerBar, player).runTaskTimer(plugin, 0, 1);
		player.setMetadata("taskID", new FixedMetadataValue(plugin, task.getTaskId()));
		player.setMetadata("bar", new FixedMetadataValue(plugin, powerBar));
}

Le Runnable correspondant est

PowerBarTask


import org.bukkit.boss.BarColor;
import org.bukkit.boss.BossBar;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;

public class PowerBarTask extends BukkitRunnable {
	BossBar bar;
	Player player;
	public PowerBarTask(BossBar bar, Player player){
		this.bar = bar;
		this.player = player;
	}
	@Override
	public void run() {
		if(bar.getProgress() == 1){
			bar.setColor(BarColor.GREEN);
			bar.removeAll();
			this.cancel();
			player.removeMetadata("taskID", Swing.getPlugin(Swing.class));
        //Nous faisons rapidement des ajustements pour la sensation de jeu décrite plus tard.
		}else if(bar.getProgress() > 0.999){
			bar.setProgress(1);
		}else if(bar.getProgress() > 0.95){
			bar.setProgress(0.9999);
			bar.setColor(BarColor.RED);
		}else{
			bar.setProgress(bar.getProgress() + 0.05);
		}
	}

}

Il est devenu. La mise en garde est que vous devez conserver l'ID de tâche dans les métadonnées ou d'une autre manière, car vous devez annuler la tâche de l'extérieur de la tâche, et lorsque vous augmentez la progression dans Runnable, si vous l'augmentez tel quel, cela provoquera une erreur de calcul. Puisqu'il ne devient pas 1, il peut être nécessaire de porter un jugement légèrement décalé. De plus, si vous masquez la barre Boss immédiatement alors que la progression devrait être de 1, il sera difficile «d'arrêter la jauge visant un réservoir plein», et du point de vue du joueur, la jauge disparaîtra avant d'être pleine. Il est facile d'avoir le sentiment d'être perdu. Il sera plus facile de jouer si vous lui donnez une marge de un à plusieurs ticks.

La jauge originale utilisant cette Boss Bar n'est pas limitée à la catégorie de reproduction sportive comme le football, mais on pense qu'elle peut être appliquée de diverses manières à des plug-ins d'autres genres tels que "l'attaque de réservoir". Pourquoi ne pas l'essayer si tu veux?

En plus de cela, un mémorandum tel que le jugement de passage à l'aide de `` Vector.isInAABB``` (sans Projectile HitEvent) et (about) la prédiction du point de chute utilisé pour créer le plug-in "HR confirmation effect" Il y a quelques astuces qui peuvent être écrites, mais comme il existe peu de méthodes d'application autres que le baseball, je vais terminer ici.

en conclusion

C'est peut-être juste mon manque de conscience, mais quand j'ai jeté un coup d'œil rapide avant de faire ce jeu de boule de neige, j'ai été surpris que le nombre de mods et plug-ins sportifs soit extrêmement petit. (En ce qui concerne MOD, j'ai pu confirmer un ensemble de plusieurs sports, mais il n'y avait presque pas de plug-in.) J'ai vu des projets où des stades et des stades ont été construits lors de la construction de villes modernes, et des projets qui reproduisent des stades réels dans Minecraft, mais la partie de l'utilisation réelle de l'architecture a été jusqu'à présent. Il semble qu'il n'ait pas fait beaucoup de progrès. (À l'origine, Snowball Game a également publié ce qu'il a fait pour son propre serveur résident où des dizaines de stades sont construits dans le monde.)

Lorsqu'on envisage de reproduire des sports dans Minecraft, il est probable que la plupart des sports seront plus amusants à faire avec plusieurs personnes qu'à le faire seul, il est donc important qu'il soit fourni sous la forme d'une prise plutôt que d'un MOD. Je pense personnellement que cela a du sens. Je serais honoré si vous pouviez utiliser les connaissances que j'ai écrites ici lorsque d'autres développeurs souhaitant créer des plug-ins sportifs apparaissent à l'avenir.

Recommended Posts

Non-physique similaire utilisé pour exprimer le baseball sur Minecraft et mise en œuvre dans Spigot (capture de balle / Conseils)
Non-physique similaire utilisé pour exprimer le baseball sur Minecraft et mise en œuvre dans Spigot (lancer / frapper)
Non-physique similaire utilisé pour exprimer le baseball sur Minecraft et mise en œuvre dans Spigot (capture de balle / Conseils)
Non-physique similaire utilisé pour exprimer le baseball sur Minecraft et mise en œuvre dans Spigot (lancer / frapper)
Apprentissage profond à partir de zéro - Conseils du chapitre 4 pour la théorie de l'apprentissage profond et la mise en œuvre apprise en Python