Inscrit le: 12 Nov 2011 Messages: 1062 Sujets: 107 Spécialité en worldedit: Inactif(Enfin presque) Médailles: 1 (En savoir plus...)
Posté le: 27/03/16 15:25 Sujet du message: Faire un déplacement en arc
Le week-end de 3 jours m'a fait revenir sur war3 parce que j'avais rien à faire et donc du coup je reviens vers vous. J'ai codé un projectile tout simple(une boule de feu) et je voudrais qu'il se déplace en arc comme la compétence mortar de D3, sauf que je n'ai pas la formule donc si quelqu'un pouvait me la donner (je met le code au cas où il faudrait que je rajoute des attributs.).
Le code:
Secret:
Jass:
library Fireball uses CONSTANTS
//CONSTANTS OF THE SPELL
globals
private constant real VELOCITY = 17.50
private constant real TIME = 0.03125000
private constant real DAMAGE_SMALL = 250.00
private constant real DAMAGE_BIG = 75.00
private constant integer DUMMY_ID = 'h000'
private timer TIMER = CreateTimer()
endglobals
//CODE
struct Fball
//ATTRIBUTES
static integer count = -1
static Fball array Instance
private unit dummy
private unit pointer_small
private unit pointer_big
private real dummy_x
private real dummy_y
private real dummy_z
private real pointer_x
private real pointer_y
private real dummy_angle
private real distance
//METHODS
private static method loop_fireball takes nothing returns nothing
local integer i = 0
local real x = 0
local real y = 0
loop
exitwhen i > Fball.count
set x = Fball.Instance[i].pointer_x - Fball.Instance[i].dummy_x
set y = Fball.Instance[i].pointer_y - Fball.Instance[i].dummy_y
if SquareRoot(x * x + y * y ) > CST_AREA_SMALL then
set x = Fball.Instance[i].dummy_x + VELOCITY * Cos(Fball.Instance[i].dummy_angle)
set y = Fball.Instance[i].dummy_y + VELOCITY * Sin(Fball.Instance[i].dummy_angle)
call SetUnitX(Fball.Instance[i].dummy, x)
call SetUnitY(Fball.Instance[i].dummy, y)
set Fball.Instance[i].dummy_x = x
set Fball.Instance[i].dummy_y = y
else
//DEALING DAMAGE
/*TO DO LATER*/
//KILLING THE DUMMIES
call KillUnit(Fball.Instance[i].dummy)
call RemoveUnit(Fball.Instance[i].pointer_small)
call RemoveUnit(Fball.Instance[i].pointer_big)
if i < Fball.count then
set Fball.Instance[i].pointer_x = Fball.Instance[Fball.count].pointer_x
set Fball.Instance[i].pointer_y = Fball.Instance[Fball.count].pointer_y
set Fball.Instance[i].pointer_small = Fball.Instance[Fball.count].pointer_small
set Fball.Instance[i].pointer_big = Fball.Instance[Fball.count].pointer_big
set Fball.Instance[i].dummy_x = Fball.Instance[Fball.count].dummy_x
set Fball.Instance[i].dummy_y = Fball.Instance[Fball.count].dummy_y
set Fball.Instance[i].dummy_z = Fball.Instance[Fball.count].dummy_z
set Fball.Instance[i].dummy_angle = Fball.Instance[Fball.count].dummy_angle
set Fball.Instance[i].dummy = Fball.Instance[Fball.count].dummy
set Fball.Instance[i].distance = Fball.Instance[Fball.count].distance
call Fball.Instance[Fball.count].deallocate()
else
call Fball.Instance[i].deallocate()
endif
set Fball.count = (Fball.count - 1)
if Fball.count == -1 then
call PauseTimer( TIMER )
endif
endif
set i = i + 1
endloop
endmethod
static method create_fireball takes player owner, real start_x, real start_y, real end_x, real end_y returns nothing
local real angle = Atan2(end_y - start_y, end_x - start_x)
local real d = SquareRoot((end_x - start_x) * (end_x - start_x) + (end_y - start_y) * (end_y - start_y))
set Fball.count = Fball.count + 1
set Instance[Fball.count] = Fball.allocate()
set Fball.Instance[Fball.count].dummy = CreateUnit( owner, DUMMY_ID, start_x, start_y, angle )
set Fball.Instance[Fball.count].dummy_angle = angle
set Fball.Instance[Fball.count].dummy_x = start_x
set Fball.Instance[Fball.count].dummy_y = start_y
set Fball.Instance[Fball.count].dummy_z = GetUnitFlyHeight( Fball.Instance[Fball.count].dummy )
set Fball.Instance[Fball.count].pointer_x = end_x
set Fball.Instance[Fball.count].pointer_y = end_y
set Fball.Instance[Fball.count].pointer_small = CreateUnit( owner, CST_POINTER_SMALL_ID, end_x, end_y, 90.00 )
set Fball.Instance[Fball.count].pointer_big = CreateUnit( owner, CST_POINTER_BIG_ID, end_x, end_y, 90.00 )
set Fball.Instance[Fball.count].distance = d
if Fball.count == 0 then
call TimerStart( TIMER, TIME, true, function Fball.loop_fireball )
call BJDebugMsg("Timer Started")
endif
endmethod
endstruct
endlibrary
En tout cas, joyeuses Pâquesà ceux qui liront ce post. _________________
Inscrit le: 09 Mar 2009 Messages: 1154 Sujets: 54 Spécialité en worldedit: Croâ ?
Posté le: 27/03/16 20:57 Sujet du message:
C'est censé être quoi pointer_x et pointer_y ?
Je ne sais pas à quoi ressemble la compétence mortar de D3, mais sinon, sans l'adapter à ton code, voici la formule d'une trajectoire de projectile (parabolique) :
En notant a l'angle de lancer (l'arc) et r la distance (sur le plan XY) parcourue :
z = ((tz - oz)/D² - tan(a)/D) * r² + tan(a) * r + oz
où oz est le z initial, tz le z final et D la distance entre le point de lancer et le point d'arrivée (sur le plan XY toujours).
Est-ce bien ce que tu cherches ? _________________
Inscrit le: 09 Mar 2009 Messages: 1154 Sujets: 54 Spécialité en worldedit: Croâ ?
Posté le: 27/03/16 21:53 Sujet du message:
Ce que tu donnes est une formule d'arc de cercle. En mathématique un arc n'est pas forcément un arc de cercle donc ce que tu dis est inexact.
De plus, étant donné ce qu'il demande on peut s'attendre à ce qu'il cherche la courbe d'une trajectoire de projectile balistique (arc parabolique donc) et pas un arc de cercle qui n'a rien à voir dans le contexte. Je pense donc que la formule que j'ai proposée est plus adaptée. _________________
C'est vrai, je viens de regarder les vidéos et cela a l'air d'être un arc légèrement parabolique.
Avec la formule que j'ai donné cela fait un arc de cercle si on interpole linéairement alpha avec le temps. En utilisant une interpolation non linéaire avec un ease-out on peut obtenir une parabole.
Demo d'interpolation: http://demos111.mootools.net/Fx.Transitions
L'algorithme correspondant pour toutes les interpolations de la démo:
Fx.Transitions.extend = function(transitions){
for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
};
Back: function(p, x){
x = x && x[0] || 1.618;
return Math.pow(p, 2) * ((x + 1) * p - x);
},
Bounce: function(p){
var value;
for (var a = 0, b = 1; 1; a += b, b /= 2){
if (p >= (7 - 4 * a) / 11){
value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);
break;
}
}
return value;
},
['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
Fx.Transitions[transition] = new Fx.Transition(function(p){
return Math.pow(p, i + 2);
});
});
L'avantage d'implémenter les interpolations c'est que l'on peut intuitivement modifier n'importe quelle fonction de géométrie pour obtenir l'effet voulu, et on peut facilement tester différente interpolation; notamment très utile pour toute animation sur le temps. _________________
Inscrit le: 09 Mar 2009 Messages: 1154 Sujets: 54 Spécialité en worldedit: Croâ ?
Posté le: 27/03/16 22:58 Sujet du message:
Peu importe la manière dont tu considères alpha en fonction du temps (peu importe la transition que tu appliques), la formule que tu as donnée reste un arc de cercle, cela ne changera que la vitesse de tracé du cercle.
Je ne suis pas sûr de voir où tu veux en venir. _________________
Inscrit le: 09 Mar 2009 Messages: 1154 Sujets: 54 Spécialité en worldedit: Croâ ?
Posté le: 28/03/16 10:07 Sujet du message:
Oui on peut dire ça, à une distance à parcourir fixée, plus a est grand et plus le projectile montera haut. En fait a représente l'angle de lancer initial comme vu sur ce schema :
Secret:
On voit également r sur le schéma, r est la distance que le projectile parcourt et dans ton cas il aura pour formule r = vitesse*t (t c'est le temps)
Ca donnerait un truc comme ça pour actualiser la position :
Jass:
local real d = speed*TIMEOUT
// On augmente la distance dist de d à chaque tick
set this.dist = this.dist + d
// On actualise x et y
set this.x = this.x + d*Cos(angle)
set this.y = this.y + d*Sin(angle)
// On actualise z en fonction de la distance dist
set this.z = ((tz - oz)/(D*D) - tan(a)/D) * this.dist*this.dist + tan(a) * this.dist + oz
TIMEOUT est la durée entre deux timers,
dist correspond à r, il est initialement à 0 (au lancer du projectile),
angle est l'orientation de la trajectoire,
D est la distance totale à parcourir (la distance entre le point de lancer et d'arrivée)
Si tu souhaites avoir la trajectoire paramétrée par la hauteur maximale du projectile plutôt que par son angle de lancer c'est tout à fait possible aussi, cela demandera de changer un peu la formule. _________________
public class RGFProjectile : MonoBehaviour
{
public float LaunchAngle = Mathf.PI / 4;
public Transform Caster;
private Vector3 Target;
public float Speed = 1.0f;
private Vector3 Origin;
// Use this for initialization
void Start()
{
Origin = (Caster != null) ? Caster.position : transform.position;
Target = Origin + Vector3.right * 10;
}
// Update is called once per frame
void Update()
{
if (transform.position != Target)
{
var offset = Target - Origin;
var launchAngleTangent = Mathf.Tan(LaunchAngle);
var squareTotalDistance = Vector2.SqrMagnitude(offset);
var deltaDistance = Speed * Time.deltaTime;
var position2D = Vector2.MoveTowards(transform.position, Target, deltaDistance);
var squareDistance2D = (position2D - (Vector2)Origin).sqrMagnitude;
var z = (offset.z / squareTotalDistance - launchAngleTangent / Mathf.Sqrt(squareTotalDistance)) * squareDistance2D + launchAngleTangent * Mathf.Sqrt(squareDistance2D) + Origin.z;
Pour l'interpolation je parle notamment d'interpoler le résultat de sin(a) avant d'appliquer le multiplicateur de distance.
z = D * Interpolation.cubic.easeOut(sin(a)) _________________
Dernière édition par Ayane le 28/03/16 14:02; édité 1 fois
Page 1 sur 1 La question posée dans ce topic a été résolue !
Vous ne pouvez pas poster de nouveaux sujets dans ce forum Vous ne pouvez pas répondre aux sujets dans ce forum Vous ne pouvez pas éditer vos messages dans ce forum Vous ne pouvez pas supprimer vos messages dans ce forum Vous ne pouvez pas voter dans les sondages de ce forum