forked from Mirrors/openclonk
reworked grappler rope physics and grappler handling, it now uses with the ropeladder a common rope library
parent
43a84d1fcb
commit
cad5661c00
Binary file not shown.
|
@ -1,20 +1,21 @@
|
|||
[DefCore]
|
||||
id=GrappleBow
|
||||
Category=C4D_Object
|
||||
Width=6
|
||||
Height=4
|
||||
Offset=-3,-2
|
||||
Vertices=3
|
||||
VertexX=0,-3,3
|
||||
VertexY=0,0,0
|
||||
VertexFriction=40,90,40
|
||||
Width=4
|
||||
Height=20
|
||||
Offset=-2,-10
|
||||
Vertices=4
|
||||
VertexX=-2,2,-2,2
|
||||
VertexY=-10,-10,10,10
|
||||
VertexFriction=100,100,100,100,100
|
||||
Picture=4,0,21,21
|
||||
Value=20
|
||||
Value=8
|
||||
Mass=10
|
||||
Collectible=1
|
||||
Components=Wood=1;Metal=1;Rope=1;
|
||||
Components=WOOD=3;
|
||||
Rebuy=1
|
||||
Rotate=1
|
||||
ContactIncinerate=5
|
||||
BlastIncinerate=30
|
||||
Float=1
|
||||
BurnTo=NONE
|
||||
Float=2
|
|
@ -1,12 +0,0 @@
|
|||
[DefCore]
|
||||
id=GrappleHelp
|
||||
Version=4,10,0,0
|
||||
Category=C4D_Vehicle
|
||||
Width=8
|
||||
Height=20
|
||||
Offset=-4,-10
|
||||
Vertices=7
|
||||
VertexX=0,0,0,-2,2,-4,4
|
||||
VertexY=2,-7,9,-3,-3,3,3
|
||||
VertexFriction=300,300,100,300,300,300,300
|
||||
Mass=50
|
Binary file not shown.
Before Width: | Height: | Size: 4.3 KiB |
|
@ -1,203 +0,0 @@
|
|||
/*
|
||||
Grapple Help
|
||||
Author: Maikel
|
||||
|
||||
Helper object to let the clonk control the rope with movement keys.
|
||||
The clonk is attached to the helper object, which is pulled by the rope.
|
||||
With the movement keys(up/down) the player is able to shorten and lengthen the rope.
|
||||
Swinging the rope can be done with left/right.
|
||||
*/
|
||||
|
||||
/*-- Locals + Get/Setters --*/
|
||||
|
||||
local bow; // Grapple bow associated with this helper object.
|
||||
local clonk; // Clonk pulled by the helper.
|
||||
local rope; // Rope connected to the helper.
|
||||
|
||||
public func SetBow(object to_bow)
|
||||
{
|
||||
bow = to_bow;
|
||||
// Helper object is inside the bow until the hooks hits solid material.
|
||||
Enter(to_bow);
|
||||
return;
|
||||
}
|
||||
|
||||
public func SetClonk(object to_clonk)
|
||||
{
|
||||
clonk = to_clonk;
|
||||
return;
|
||||
}
|
||||
|
||||
public func GetClonk()
|
||||
{
|
||||
return clonk;
|
||||
}
|
||||
|
||||
public func SetRope(object to_rope)
|
||||
{
|
||||
rope = to_rope;
|
||||
return;
|
||||
}
|
||||
|
||||
public func GetRope()
|
||||
{
|
||||
return rope;
|
||||
}
|
||||
|
||||
/*-- Misc --*/
|
||||
|
||||
// Called from hook to hang the clonk on the helper object.
|
||||
public func HangClonkOntoMe()
|
||||
{
|
||||
Exit(0, 10);
|
||||
SetXDir(clonk->GetXDir());
|
||||
SetYDir(clonk->GetYDir());
|
||||
clonk->SetAction("Idle");
|
||||
clonk->SetAction("HangOnto", this);
|
||||
return;
|
||||
}
|
||||
|
||||
// Called from the rope to notify the helper that the rope snapped.
|
||||
public func OnRopeBreak()
|
||||
{
|
||||
bow->OnRopeBreak();
|
||||
RemoveObject();
|
||||
return;
|
||||
}
|
||||
|
||||
// Called from the clonk to notify the helper that the clonk has let go of the helper.
|
||||
public func HangOntoLost(object clonk)
|
||||
{
|
||||
if (rope)
|
||||
rope->BreakRope();
|
||||
RemoveObject();
|
||||
return;
|
||||
}
|
||||
|
||||
protected func Destruction()
|
||||
{
|
||||
if (clonk)
|
||||
{
|
||||
if (this == clonk->GetActionTarget())
|
||||
{
|
||||
clonk->SetAction("Jump");
|
||||
// Pass speed onto clonk.
|
||||
clonk->SetXDir(GetXDir());
|
||||
clonk->SetYDir(GetYDir());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Overload of GetMass() to return the clonks mass.
|
||||
public func GetMass()
|
||||
{
|
||||
if (!clonk)
|
||||
return GetMass();
|
||||
return clonk->GetMass();
|
||||
}
|
||||
|
||||
/*-- Grapple rope controls --*/
|
||||
|
||||
public func ControlUp()
|
||||
{
|
||||
// Shorten rope.
|
||||
if (rope)
|
||||
{
|
||||
var fxnum = GetEffect("IntGrappleControl", this);
|
||||
if (!fxnum)
|
||||
fxnum = AddEffect("IntGrappleControl", this, 100, 1, this);
|
||||
EffectVar(0, this, fxnum) = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public func ControlDown()
|
||||
{
|
||||
// Lengthen rope.
|
||||
if (rope)
|
||||
{
|
||||
var fxnum = GetEffect("IntGrappleControl", this);
|
||||
if (!fxnum)
|
||||
fxnum = AddEffect("IntGrappleControl", this, 100, 1, this);
|
||||
EffectVar(1, this, fxnum) = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public func ControlLeft()
|
||||
{
|
||||
clonk->SetDir(DIR_Left);
|
||||
var fxnum = GetEffect("IntGrappleControl", this);
|
||||
if (!fxnum)
|
||||
fxnum = AddEffect("IntGrappleControl", this, 100, 1, this);
|
||||
EffectVar(2, this, fxnum) = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public func ControlRight()
|
||||
{
|
||||
clonk->SetDir(DIR_Right);
|
||||
var fxnum = GetEffect("IntGrappleControl", this);
|
||||
if (!fxnum)
|
||||
fxnum = AddEffect("IntGrappleControl", this, 100, 1, this);
|
||||
EffectVar(3, this, fxnum) = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public func ControlStop(object clonk, int control)
|
||||
{
|
||||
var fxnum = GetEffect("IntGrappleControl", this);
|
||||
if (!fxnum)
|
||||
return true;
|
||||
if (control == CON_Up) EffectVar(0, this, fxnum) = false;
|
||||
if (control == CON_Down) EffectVar(1, this, fxnum) = false;
|
||||
if (control == CON_Left) EffectVar(2, this, fxnum) = false;
|
||||
if (control == CON_Right) EffectVar(3, this, fxnum) = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Effect for smooth movement.
|
||||
public func FxIntGrappleControlTimer(object target, int fxnum)
|
||||
{
|
||||
if (!EffectVar(0, this, fxnum) && !EffectVar(1, this, fxnum)
|
||||
&& !EffectVar(2, this, fxnum) && !EffectVar(3, this, fxnum))
|
||||
return -1;
|
||||
|
||||
// Movement.
|
||||
if (EffectVar(0, this, fxnum))
|
||||
if (rope)
|
||||
rope->DoLength(-1);
|
||||
if (EffectVar(1, this, fxnum))
|
||||
if (rope)
|
||||
rope->DoLength(+1);
|
||||
if (EffectVar(2, this, fxnum))
|
||||
SetXDir(GetXDir(100) - 5, 100);
|
||||
if (EffectVar(3, this, fxnum))
|
||||
SetXDir(GetXDir(100) + 5, 100);
|
||||
return FX_OK;
|
||||
}
|
||||
|
||||
// Turn when control using objects.
|
||||
public func ControlUseHolding(object clonk, int x, int y)
|
||||
{
|
||||
return ControlUseTurn(clonk, x, y);
|
||||
}
|
||||
|
||||
public func ControlUseAltHolding(object clonk, int x, int y)
|
||||
{
|
||||
return ControlUseTurn(clonk, x, y);
|
||||
}
|
||||
|
||||
private func ControlUseTurn(object clonk, int x, int y)
|
||||
{
|
||||
if (x > 0)
|
||||
if (clonk->GetDir() == DIR_Left)
|
||||
clonk->SetDir(DIR_Right);
|
||||
|
||||
if (x < 0)
|
||||
if (clonk->GetDir() == DIR_Right)
|
||||
clonk->SetDir(DIR_Left);
|
||||
|
||||
return false;
|
||||
}
|
|
@ -2,11 +2,12 @@
|
|||
id=GrappleHook
|
||||
Version=4,10,0,0
|
||||
Category=C4D_Vehicle
|
||||
Width=6
|
||||
Height=7
|
||||
Offset=-3,-4
|
||||
Width=5
|
||||
Height=6
|
||||
Offset=-3,0
|
||||
Vertices=3
|
||||
VertexY=-3,2,0
|
||||
VertexY=+3,2,0
|
||||
VertexX=0,0,0
|
||||
VertexFriction=120,120,120
|
||||
Value=15
|
||||
Mass=15
|
||||
|
|
Binary file not shown.
|
@ -1,35 +1,40 @@
|
|||
/*
|
||||
Grapple Hook
|
||||
Author: Maikel
|
||||
Author: Randrian
|
||||
|
||||
The hook can be shot with the grappling bow.
|
||||
On impact the hook will
|
||||
On impact the hook will stick to the ground
|
||||
The hook also controls the swinging controls for the clonk
|
||||
*/
|
||||
|
||||
local rope; // The rope is the connection between the hook and the helper object.
|
||||
local help; // The clonk is attached to the helper object.
|
||||
local rope; // The rope is the connection between the hook
|
||||
local clonk;
|
||||
local pull;
|
||||
|
||||
public func ArrowStrength() { return 10; }
|
||||
|
||||
protected func Construction()
|
||||
public func GetRope() { return rope; }
|
||||
|
||||
public func New(object new_clonk, object new_rope)
|
||||
{
|
||||
SetR(90);
|
||||
return _inherited(...);
|
||||
SetObjDrawTransform(0, 1, 0, 0, 0, 0, 0); // Hide
|
||||
clonk = new_clonk;
|
||||
rope = new_rope;
|
||||
}
|
||||
|
||||
public func Launch(int angle, int str, object shooter, object bow)
|
||||
{
|
||||
SetObjDrawTransform(0, 1, 0, 0, 0, 0, 0); // Hide
|
||||
Exit();
|
||||
|
||||
// Create rope and helper object.
|
||||
rope = CreateObject(GrappleRope, 0, 0, NO_OWNER);
|
||||
help = CreateObject(GrappleHelp, 0, 0, NO_OWNER);
|
||||
|
||||
rope->ConnectFree(this, help);
|
||||
help->SetBow(bow);
|
||||
help->SetClonk(shooter);
|
||||
help->SetRope(rope);
|
||||
bow->SetHelp(help);
|
||||
pull = 0;
|
||||
|
||||
// Create rope
|
||||
rope = CreateObject(GrappleRope, 0, 0, NO_OWNER);
|
||||
|
||||
rope->Connect(this, bow);
|
||||
rope->ConnectLoose();
|
||||
clonk = shooter;
|
||||
|
||||
var xdir = Sin(angle,str);
|
||||
var ydir = Cos(angle,-str);
|
||||
|
@ -41,6 +46,12 @@ public func Launch(int angle, int str, object shooter, object bow)
|
|||
AddEffect("InFlight", this, 1, 1, this);
|
||||
}
|
||||
|
||||
public func Destruction()
|
||||
{
|
||||
if(rope)
|
||||
rope->HookRemoved();
|
||||
}
|
||||
|
||||
private func Stick()
|
||||
{
|
||||
if (GetEffect("InFlight",this))
|
||||
|
@ -57,7 +68,6 @@ private func Stick()
|
|||
var y = Cos(GetR(), -9);
|
||||
if(GBackSolid(x,y) && 1)
|
||||
{
|
||||
//Log("Attach hook");
|
||||
// stick in landscape
|
||||
SetVertex(2,VTX_Y,-12,2);
|
||||
SetVertex(3,VTX_X,-3,2);
|
||||
|
@ -71,12 +81,25 @@ private func Stick()
|
|||
}
|
||||
|
||||
if (rope)
|
||||
rope->ConnectPull();
|
||||
if (help)
|
||||
help->HangClonkOntoMe();
|
||||
ScheduleCall(this, "StartPull", 5);
|
||||
}
|
||||
}
|
||||
|
||||
public func StartPull()
|
||||
{
|
||||
pull = 1;
|
||||
|
||||
AddEffect("IntGrappleControl", clonk, 1, 1, this);
|
||||
if(clonk->GetAction() == "Jump")
|
||||
{
|
||||
rope->HockAnchored(1);
|
||||
EffectVar(5, clonk, GetEffect("IntGrappleControl", clonk)) = 1;
|
||||
EffectVar(6, clonk, GetEffect("IntGrappleControl", clonk)) = 10;
|
||||
}
|
||||
else
|
||||
rope->HockAnchored();
|
||||
}
|
||||
|
||||
public func Hit()
|
||||
{
|
||||
Stick();
|
||||
|
@ -127,10 +150,135 @@ public func Entrance(object container)
|
|||
|
||||
public func OnRopeBreak()
|
||||
{
|
||||
RemoveEffect("IntGrappleControl", clonk);
|
||||
RemoveObject();
|
||||
return;
|
||||
}
|
||||
|
||||
protected func Definition(def) {
|
||||
SetProperty("Name", "$Name$", def);
|
||||
}
|
||||
|
||||
|
||||
/*-- Grapple rope controls --*/
|
||||
|
||||
public func FxIntGrappleControlControl(object target, int fxnum, ctrl, x,y,strength, repeat, release)
|
||||
{
|
||||
if(ctrl != CON_Up && ctrl != CON_Down && ctrl != CON_Right && ctrl != CON_Left) return;
|
||||
|
||||
if(ctrl == CON_Right)
|
||||
{
|
||||
EffectVar(3, target, fxnum) = !release;
|
||||
}
|
||||
if(ctrl == CON_Left)
|
||||
{
|
||||
EffectVar(2, target, fxnum) = !release;
|
||||
}
|
||||
if(ctrl == CON_Up)
|
||||
{
|
||||
EffectVar(0, target, fxnum) = !release;
|
||||
if(target->GetAction() == "Jump" && !release && pull)
|
||||
rope->ConnectPull();
|
||||
}
|
||||
if(ctrl == CON_Down)
|
||||
{
|
||||
EffectVar(1, target, fxnum) = !release;
|
||||
}
|
||||
}
|
||||
|
||||
local iSwingAnimation;
|
||||
|
||||
// Effect for smooth movement.
|
||||
public func FxIntGrappleControlTimer(object target, int fxnum, int time)
|
||||
{
|
||||
|
||||
// Movement.
|
||||
if (EffectVar(0, target, fxnum))
|
||||
if (rope && time%2 == 0)
|
||||
rope->DoLength(-1);
|
||||
if (EffectVar(1, target, fxnum))
|
||||
if (rope)
|
||||
rope->DoLength(+1);
|
||||
if (EffectVar(2, target, fxnum))
|
||||
{
|
||||
rope->DoSpeed(-50);
|
||||
SetXDir(GetXDir(100) - 1000, 100);
|
||||
}
|
||||
if (EffectVar(3, target, fxnum))
|
||||
{
|
||||
rope->DoSpeed(+50);
|
||||
SetXDir(GetXDir(100) + 1000, 100);
|
||||
}
|
||||
|
||||
if(target->GetAction() != "Jump")
|
||||
{
|
||||
if(rope->GetConnectStatus())
|
||||
rope->ConnectLoose();
|
||||
}
|
||||
|
||||
if(target->GetAction() == "Jump" && rope->GetConnectStatus() && !EffectVar(6, target, fxnum))
|
||||
{
|
||||
if(!EffectVar(4, target, fxnum))
|
||||
target->SetTurnType(1);
|
||||
target->SetObjDrawTransform(1000, 0, 3000*(1-2*target->GetDir()), 0, 1000);
|
||||
|
||||
if(EffectVar(0, target, fxnum))
|
||||
{
|
||||
if(EffectVar(4, target, fxnum) != 2)
|
||||
{
|
||||
EffectVar(4, target, fxnum) = 2;
|
||||
target->PlayAnimation("RopeClimb", 10, Anim_Linear(target->GetAnimationLength("RopeClimb")/2, 0, target->GetAnimationLength("RopeClimb"), 35), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
|
||||
}
|
||||
}
|
||||
else if(EffectVar(1, target, fxnum))
|
||||
{
|
||||
if(EffectVar(4, target, fxnum) != 3)
|
||||
{
|
||||
EffectVar(4, target, fxnum) = 3;
|
||||
target->PlayAnimation("RopeDown", 10, Anim_Const(0), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
|
||||
}
|
||||
}
|
||||
else if(EffectVar(2, target, fxnum) || EffectVar(3, target, fxnum))
|
||||
{
|
||||
var start = target->GetAnimationLength("RopeSwing")/2;
|
||||
var length = target->GetAnimationLength("RopeSwing");
|
||||
var dir = 0;
|
||||
if( (EffectVar(2, target, fxnum) && !target->GetDir())
|
||||
|| (!EffectVar(2, target, fxnum) && target->GetDir())
|
||||
) dir = 1;
|
||||
if(EffectVar(4, target, fxnum) != 4+dir)
|
||||
{
|
||||
iSwingAnimation = target->PlayAnimation("RopeSwing", 10, Anim_Linear(start, length*dir, length*(!dir), 35, ANIM_Hold), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
|
||||
EffectVar(4, target, fxnum) = 4+dir;
|
||||
}
|
||||
}
|
||||
else if(EffectVar(4, target, fxnum) != 1)
|
||||
{
|
||||
EffectVar(4, target, fxnum) = 1;
|
||||
target->PlayAnimation("OnRope", 10, Anim_Linear(0, 0, target->GetAnimationLength("OnRope"), 35*2, ANIM_Loop), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
|
||||
}
|
||||
var angle = rope->GetClonkAngle();
|
||||
var off = rope->GetClonkOff();
|
||||
target->SetProperty("MeshTransformation", Trans_Mul(Trans_Translate(0, -10000), Trans_Rotate(angle,0,0,1), Trans_Translate(-off[0],-off[1]+10000)));
|
||||
}
|
||||
else if(EffectVar(4, target, fxnum))
|
||||
{
|
||||
target->SetProperty("MeshTransformation");
|
||||
target->SetObjDrawTransform(1000, 0, 0, 0, 1000);
|
||||
target->StopAnimation(target->GetRootAnimation(10));
|
||||
EffectVar(4, target, fxnum) = 0;
|
||||
}
|
||||
|
||||
if(EffectVar(6, target, fxnum)) EffectVar(6, target, fxnum)--;
|
||||
|
||||
return FX_OK;
|
||||
}
|
||||
|
||||
public func FxIntGrappleControlStop(object target, int fxnum, int reason, int tmp)
|
||||
{
|
||||
if(tmp) return;
|
||||
target->SetTurnType(0);
|
||||
target->SetProperty("MeshTransformation");
|
||||
target->StopAnimation(target->GetRootAnimation(10));
|
||||
target->SetObjDrawTransform();
|
||||
}
|
|
@ -3,5 +3,9 @@ id=GrappleRope
|
|||
Version=4,10,0,0
|
||||
Category=C4D_StaticBack
|
||||
Vertices=2
|
||||
Line=C4D_LineRope
|
||||
LineIntersect=0
|
||||
#Line=C4D_LineRope
|
||||
#LineIntersect=0
|
||||
Width=5
|
||||
Height=12
|
||||
Offset=-1,-6
|
||||
Picture=0,0,36,32
|
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.3 KiB |
|
@ -1,204 +1,258 @@
|
|||
/*
|
||||
Grapple Rope
|
||||
Author: Maikel
|
||||
Author: Randrian
|
||||
|
||||
The rope used for grappling devices.
|
||||
Call BreakRope() to snap the rope.
|
||||
Calls "OnRopeBreak" in both action targets when the rope snaps.
|
||||
Rope snaps on overtension and bending (>5 vertices).
|
||||
TODO: mix both, breaking should depend on a combination of both tension and bending.
|
||||
Connect(obj1, obj2) connects two objects
|
||||
BreakRope() breaks the rope
|
||||
DrawIn() draws the hook in
|
||||
*/
|
||||
|
||||
/*-- Rope length --*/
|
||||
#include Library_Rope
|
||||
|
||||
local length; // The physical length of the rope.
|
||||
static const Rope_Iterations = 10;
|
||||
static const Rope_Precision = 100;
|
||||
static const Rope_PointDistance = 10;
|
||||
|
||||
// The maximal physical length of the rope.
|
||||
private func RopeMaxLength() { return 400; }
|
||||
static const Weight = 1;
|
||||
|
||||
// Functions to modify the physical rope length.
|
||||
public func GetLength() { return length; }
|
||||
public func SetLength(int newlength) { length = BoundBy(newlength, 0, RopeMaxLength()); return; }
|
||||
public func DoLength(int dolength) { length += dolength; length = BoundBy(length, 0, RopeMaxLength()); return; }
|
||||
|
||||
// Call this to set physical rope length to vertex length.
|
||||
public func SetToVertexLength() { length = VertexLength(); return; }
|
||||
|
||||
// Calculates the the vertex length of the rope.
|
||||
private func VertexLength()
|
||||
// Call this to break the rope.
|
||||
public func BreakRope()
|
||||
{
|
||||
var len = 0;
|
||||
for (var i = 0; i < GetVertexNum() - 1; i++)
|
||||
len += Distance (
|
||||
GetVertex (i, VTX_X),
|
||||
GetVertex (i, VTX_Y),
|
||||
GetVertex (i + 1, VTX_X),
|
||||
GetVertex (i + 1, VTX_Y));
|
||||
return len;
|
||||
if(length == -1) return;
|
||||
length = -1;
|
||||
var act1 = objects[0][0];
|
||||
var act2 = objects[1][0];
|
||||
SetAction("Idle");
|
||||
// notify action targets.
|
||||
if (act1 != nil)
|
||||
act1->~OnRopeBreak();
|
||||
if (act2 != nil)
|
||||
act2->~OnRopeBreak();
|
||||
RemoveRope();
|
||||
RemoveObject();
|
||||
return;
|
||||
}
|
||||
|
||||
/* --------------------- Callbacks form the rope ---------------------- */
|
||||
|
||||
/* To be overloaded for special segment behaviour */
|
||||
private func CreateSegment(int index, object previous)
|
||||
{
|
||||
if(index == 0) return;
|
||||
var segment;
|
||||
segment = CreateObject(GrappleRope);
|
||||
return segment;
|
||||
}
|
||||
|
||||
/*-- Rope connecting --*/
|
||||
|
||||
// Connects two objects to the rope, but the length will vary on their positions.
|
||||
public func ConnectFree(object obj1, object obj2)
|
||||
public func Connect(object obj1, object obj2)
|
||||
{
|
||||
SetAction("ConnectFree", obj1, obj2);
|
||||
return;
|
||||
}
|
||||
StartRopeConnect(obj1, obj2);
|
||||
Max_Length = 100;
|
||||
HoockAnchored = 0;
|
||||
|
||||
// Connects two objects to the rope, which will try to keep constant length.
|
||||
public func ConnectPull(object obj1, object obj2)
|
||||
{
|
||||
length = VertexLength();
|
||||
SetAction("ConnectPull", obj1, obj2);
|
||||
return;
|
||||
}
|
||||
|
||||
/*-- Rope pulling --*/
|
||||
|
||||
private func RopeStrength() { return 40; } // How much a rope can maximally be stretched in % of the physical length.
|
||||
private func RopeElasticity() { return 100; } // Defines stretching of the rope.
|
||||
|
||||
protected func PullObjects()
|
||||
{
|
||||
// Break rope on bending -> more than 5 vertices.
|
||||
if (GetVertexNum() > 5)
|
||||
{
|
||||
Log("Rope break: overbending");
|
||||
return BreakRope();
|
||||
}
|
||||
|
||||
// Check rope strength.
|
||||
if (100 * dif > RopeStrength() * (length + 10))
|
||||
{
|
||||
Log("Rope break: overtension");
|
||||
return BreakRope();
|
||||
}
|
||||
|
||||
// Only if vertex length larger than physical length.
|
||||
var vlen = VertexLength();
|
||||
var dif = vlen - length;
|
||||
if (dif < 0)
|
||||
{
|
||||
length = vlen;
|
||||
return;
|
||||
}
|
||||
|
||||
// Rope to short.
|
||||
if (vlen < 12)
|
||||
return BreakRope();
|
||||
|
||||
// Get objects.
|
||||
var obj1 = GetActionTarget(0);
|
||||
var obj2 = GetActionTarget(1);
|
||||
|
||||
// Object positions.
|
||||
var o1x = obj1->GetX();
|
||||
var o1y = obj1->GetY();
|
||||
var o2x = obj2->GetX();
|
||||
var o2y = obj2->GetY();
|
||||
|
||||
// Get containers.
|
||||
while (obj1->Contained())
|
||||
obj1 = obj1->Contained();
|
||||
while (obj2->Contained())
|
||||
obj2 = obj2->Contained();
|
||||
|
||||
// Check movability.
|
||||
var mov1 = 50;
|
||||
var mov2 = 50;
|
||||
if (obj1->Stuck() || obj1->GetCategory() & (C4D_StaticBack | C4D_Structure))
|
||||
{
|
||||
mov1 = 0;
|
||||
mov2 *= 2;
|
||||
}
|
||||
if (obj2->Stuck() || obj2->GetCategory() & (C4D_StaticBack | C4D_Structure))
|
||||
{
|
||||
mov1 *= 2;
|
||||
mov2 = 0;
|
||||
}
|
||||
if (!mov1 && !mov2)
|
||||
return;
|
||||
|
||||
// Get vertex coordinates.
|
||||
var v1x = GetVertex(1, VTX_X);
|
||||
var v1y = GetVertex(1, VTX_Y);
|
||||
var v2x = GetVertex(GetVertexNum() - 2, VTX_X);
|
||||
var v2y = GetVertex(GetVertexNum() - 2, VTX_Y);
|
||||
|
||||
// Angles.
|
||||
var ang1 = Angle(v1x, v1y, o1x, o1y);
|
||||
var ang2 = Angle(v2x, v2y, o2x, o2y);
|
||||
|
||||
// Mass.
|
||||
var mass1 = Max(5, obj1->GetMass());
|
||||
var mass2 = Max(5, obj2->GetMass());
|
||||
|
||||
// Calculate rope acceleration.
|
||||
var acc1 = 200 * dif * mov1 * RopeElasticity();
|
||||
var acc2 = 200 * dif * mov2 * RopeElasticity();
|
||||
acc1 /= 10 * mass1 * (length + 10);
|
||||
acc2 /= 10 * mass2 * (length + 10);
|
||||
SetAction("Hide");
|
||||
|
||||
// Artificial energy loss.
|
||||
var xdir1 = 39 * obj1->GetXDir(1000) / 40;
|
||||
var ydir1 = 39 * obj1->GetYDir(1000) / 40;
|
||||
var xdir2 = 39 * obj2->GetXDir(1000) / 40;
|
||||
var ydir2 = 39 * obj2->GetYDir(1000) / 40;
|
||||
|
||||
// Accelerate objects.
|
||||
obj1->SetXDir(xdir1 - Sin(ang1, acc1), 1000);
|
||||
obj1->SetYDir(ydir1 + Cos(ang1, acc1), 1000);
|
||||
obj2->SetXDir(xdir2 - Sin(ang2, acc2), 1000);
|
||||
obj2->SetYDir(ydir2 + Cos(ang2, acc2), 1000);
|
||||
|
||||
AddEffect("IntHang", this, 1, 1, this);
|
||||
return;
|
||||
}
|
||||
|
||||
/*-- Other --*/
|
||||
public func GetConnectStatus() { return !length_auto; }
|
||||
|
||||
protected func Initialize()
|
||||
local HoockAnchored;
|
||||
|
||||
/* Callback form the hook, when it hits ground */
|
||||
public func HockAnchored(bool pull)
|
||||
{
|
||||
SetVertex(0, VTX_X, GetX()); SetVertex(0, VTX_Y, GetY());
|
||||
SetVertex(1, VTX_X, GetX()); SetVertex(1, VTX_Y, GetY());
|
||||
return;
|
||||
if(pull)
|
||||
ConnectPull();
|
||||
HoockAnchored = 1;
|
||||
}
|
||||
|
||||
// Call this to break the rope.
|
||||
public func BreakRope()
|
||||
public func HookRemoved()
|
||||
{
|
||||
var act1 = GetActionTarget(0);
|
||||
var act2 = GetActionTarget(1);
|
||||
SetAction("Idle");
|
||||
// notify action targets.
|
||||
if (act1)
|
||||
act1->~OnRopeBreak();
|
||||
if (act2)
|
||||
act2->~OnRopeBreak();
|
||||
RemoveObject();
|
||||
return;
|
||||
var new_hook = CreateObject(GrappleHook);
|
||||
new_hook->New(objects[1][0]->Contained(), this);
|
||||
objects[1][0]->SetHook(new_hook);
|
||||
objects[0][0] = new_hook;
|
||||
DrawIn();
|
||||
}
|
||||
|
||||
/* Callback form the rope library */
|
||||
public func MaxLengthReached()
|
||||
{
|
||||
var clonk = objects[1][0];
|
||||
if(clonk->Contained()) clonk = clonk->Contained();
|
||||
if(!HoockAnchored)
|
||||
DrawIn();
|
||||
else if(!clonk->GetContact(-1))
|
||||
{
|
||||
ConnectPull();
|
||||
}
|
||||
}
|
||||
|
||||
/* for swinging */
|
||||
func DoSpeed(int value)
|
||||
{
|
||||
particles[-1][1][0] -= value;
|
||||
}
|
||||
|
||||
func FxIntHangTimer() { TimeStep(); }
|
||||
|
||||
func FxDrawInTimer()
|
||||
{
|
||||
if(length < 15)
|
||||
{
|
||||
BreakRope();
|
||||
return -1;
|
||||
}
|
||||
DoLength(-5);
|
||||
}
|
||||
|
||||
func DrawIn()
|
||||
{
|
||||
if(!GetEffect("DrawIn", this)) AddEffect("DrawIn", this, 1, 1, this);
|
||||
SetFixed(0, 1);
|
||||
ConnectPull();
|
||||
var clonk = objects[1][0];
|
||||
if(clonk->Contained()) clonk = clonk->Contained();
|
||||
RemoveEffect("IntGrappleControl", clonk);
|
||||
}
|
||||
|
||||
func ConnectPull()
|
||||
{
|
||||
if(length_auto == 1 && objects[1][1])
|
||||
{
|
||||
var obj = objects[1][0];
|
||||
if(obj->Contained()) obj = obj->Contained();
|
||||
// Vector r of the last segment
|
||||
var r = Vec_Sub(particles[-1][0],particles[-3][0]);
|
||||
r = [-r[1], r[0]]; // Get the orthogonal vector
|
||||
r = Vec_Normalize(r, 100); // Make it lenght 0
|
||||
var v = [obj->GetXDir(Rope_Precision), obj->GetYDir(Rope_Precision)]; // Get the speed vector
|
||||
var projection = Vec_Dot(r, Vec_Mul(v, 100))/10000; // Projekt the speed on the orthogonal vector
|
||||
obj->SetXDir(r[0]*projection/100, Rope_Precision);
|
||||
obj->SetYDir(r[1]*projection/100, Rope_Precision);
|
||||
}
|
||||
if(length_auto && objects[1][1])
|
||||
{
|
||||
var obj = objects[1][0];
|
||||
if(obj->Contained()) obj = obj->Contained();
|
||||
particles[-1][1][0] = particles[-1][0][0]-obj->SetXDir(Rope_Precision);
|
||||
particles[-1][1][1] = particles[-1][0][1]-obj->SetYDir(Rope_Precision);
|
||||
}
|
||||
_inherited(...);
|
||||
AccumulateForces();
|
||||
TimeStep();
|
||||
}
|
||||
|
||||
local hook_angle;
|
||||
|
||||
func UpdateLines()
|
||||
{
|
||||
var fTimeStep = 1;
|
||||
var oldangle;
|
||||
for(var i=1; i < ParticleCount; i++)
|
||||
{
|
||||
// Update the Position of the Segment
|
||||
segments[i]->SetPosition(GetPartX(i), GetPartY(i));
|
||||
|
||||
// Calculate the angle to the previous segment
|
||||
var angle = Angle(particles[i][0][0], particles[i][0][1], particles[i-1][0][0], particles[i-1][0][1]);
|
||||
|
||||
// Draw the left line
|
||||
var start = particles[i-1][0];
|
||||
var end = particles[i][0];
|
||||
|
||||
if(i == 1 && ParticleCount > 2)
|
||||
{
|
||||
angle = Angle(particles[2][0][0], particles[2][0][1], particles[0][0][0], particles[0][0][1]);
|
||||
end = particles[0][0];
|
||||
end[0] += -Sin(angle, 45*Rope_Precision/10);
|
||||
end[1] += +Cos(angle, 45*Rope_Precision/10);
|
||||
}
|
||||
|
||||
if(i == 2)
|
||||
{
|
||||
angle = Angle(particles[2][0][0], particles[2][0][1], particles[0][0][0], particles[0][0][1]);
|
||||
start = particles[0][0];
|
||||
start[0] += -Sin(angle, 45*Rope_Precision/10);
|
||||
start[1] += +Cos(angle, 45*Rope_Precision/10);
|
||||
}
|
||||
|
||||
var diff = Vec_Sub(end,start);
|
||||
var diffangle = Vec_Angle(diff, [0,0]);
|
||||
var point = Vec_Add(start, Vec_Div(diff, 2));
|
||||
var length = Vec_Length(diff)*1000/Rope_Precision/10;
|
||||
|
||||
if(i == 1)
|
||||
{
|
||||
segments[i]->SetGraphics(nil, GrappleHook);
|
||||
point[0] += -Cos(diffangle, 15*Rope_Precision/10)+Sin(diffangle, 4*Rope_Precision);
|
||||
point[1] += -Cos(diffangle, 4*Rope_Precision)-Sin(diffangle, 15*Rope_Precision/10);
|
||||
length = 1000;
|
||||
}
|
||||
|
||||
SetLineTransform(segments[i], -diffangle, point[0]*10-GetPartX(i)*1000,point[1]*10-GetPartY(i)*1000, length );
|
||||
|
||||
// Remember the angle
|
||||
oldangle = angle;
|
||||
}
|
||||
}
|
||||
|
||||
func GetClonkAngle()
|
||||
{
|
||||
if(ParticleCount > 3)
|
||||
return Angle(particles[-1][0][0], particles[-1][0][1], particles[-3][0][0], particles[-3][0][1]);
|
||||
}
|
||||
|
||||
local ClonkOldSpeed;
|
||||
|
||||
func GetClonkOff()
|
||||
{
|
||||
var clonk = objects[1][0];
|
||||
var speed = [clonk->GetXDir(Rope_Precision), clonk->GetYDir(Rope_Precision)];
|
||||
var offset = speed;
|
||||
offset[0] = offset[0]*1000/Rope_Precision;
|
||||
offset[1] = offset[1]*1000/Rope_Precision;
|
||||
if(!ClonkOldSpeed)
|
||||
{
|
||||
ClonkOldSpeed = offset;
|
||||
}
|
||||
var ret = ClonkOldSpeed;
|
||||
ClonkOldSpeed = offset;
|
||||
return ret;
|
||||
}
|
||||
|
||||
func SetSegmentTransform(obj, int r, int xoff, int yoff, int length) {
|
||||
var fsin=Sin(r, 1000), fcos=Cos(r, 1000); //length = 1200;
|
||||
// set matrix values
|
||||
obj->SetObjDrawTransform (
|
||||
+fcos, +fsin*length/1200, xoff,
|
||||
-fsin, +fcos*length/1200, yoff,
|
||||
);
|
||||
}
|
||||
|
||||
func SetLineTransform(obj, int r, int xoff, int yoff, int length, int layer, int MirrorSegments) {
|
||||
if(!MirrorSegments) MirrorSegments = 1;
|
||||
var fsin=Sin(r, 1000), fcos=Cos(r, 1000);
|
||||
// set matrix values
|
||||
obj->SetObjDrawTransform (
|
||||
+fcos*MirrorSegments, +fsin*length/1000, xoff,
|
||||
-fsin*MirrorSegments, +fcos*length/1000, yoff,layer
|
||||
);
|
||||
}
|
||||
|
||||
protected func Definition(def) {
|
||||
SetProperty("Name", "$Name$", def);
|
||||
SetProperty("LineColors", [RGB(66,33,00) , RGB(66,33,00)], def);
|
||||
SetProperty("ActMap", {
|
||||
ConnectFree = {
|
||||
Hide = {
|
||||
Prototype = Action,
|
||||
Name = "ConnectFree",
|
||||
Procedure = DFA_CONNECT,
|
||||
FacetBase = 1,
|
||||
NextAction = "ConnectFree",
|
||||
},
|
||||
ConnectPull = {
|
||||
Prototype = Action,
|
||||
Name = "ConnectPull",
|
||||
Procedure = DFA_CONNECT,
|
||||
Length = 1,
|
||||
Delay = 1,
|
||||
FacetBase = 1,
|
||||
NextAction = "ConnectPull",
|
||||
StartCall = "PullObjects",
|
||||
Name = "Hide",
|
||||
},
|
||||
}, def);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Grapple Bow
|
||||
Author: Maikel
|
||||
Author: Randrian
|
||||
|
||||
A crossbow which is enabled to fire grappling hooks, also has a winching system.
|
||||
*/
|
||||
|
@ -18,11 +18,11 @@ public func SetHelp(object tohelp)
|
|||
return;
|
||||
}
|
||||
|
||||
public func GetCarryMode() { return CARRY_HandBack; }
|
||||
public func GetCarryMode() { if(hook->Contained() == nil) return CARRY_Back; return CARRY_HandBack; }
|
||||
|
||||
public func GetCarrySpecial(clonk) { if(fAiming) return "pos_hand2"; }
|
||||
public func GetCarryBone2(clonk) { return "main2"; }
|
||||
public func GetCarryMode(clonk) { if(fAiming >= 0) return CARRY_Grappler; }
|
||||
public func GetCarryMode(clonk) { if(hook->Contained() == nil) return CARRY_Back; if(fAiming >= 0) return CARRY_Grappler; }
|
||||
|
||||
/* +++++++++++ Controls ++++++++++++++ */
|
||||
|
||||
|
@ -36,9 +36,6 @@ func Initialize()
|
|||
animation_set = {
|
||||
AimMode = AIM_Position, // The aiming animation is done by adjusting the animation position to fit the angle
|
||||
AnimationAim = "CrossbowAimArms",
|
||||
// AnimationLoad = "BowLoadArms",
|
||||
// LoadTime = 10,
|
||||
// LoadTime2 = 5*10/20,
|
||||
AnimationShoot = nil,
|
||||
ShootTime = 20,
|
||||
TurnType = 1,
|
||||
|
@ -49,6 +46,11 @@ func Initialize()
|
|||
OnRopeBreak();
|
||||
}
|
||||
|
||||
public func SetHook(object new_hook)
|
||||
{
|
||||
hook = new_hook;
|
||||
}
|
||||
|
||||
public func OnRopeBreak()
|
||||
{
|
||||
if(hook_attach)
|
||||
|
@ -60,18 +62,33 @@ public func OnRopeBreak()
|
|||
PlayAnimation("Load", 5, Anim_Const(GetAnimationLength("Load")), Anim_Const(1000));
|
||||
}
|
||||
|
||||
protected func Destruction()
|
||||
{
|
||||
var rope = hook->GetRope();
|
||||
if (rope)
|
||||
rope->BreakRope();
|
||||
}
|
||||
|
||||
protected func Departure()
|
||||
{
|
||||
var rope = hook->GetRope();
|
||||
if (rope)
|
||||
rope->DrawIn();
|
||||
}
|
||||
|
||||
public func GetAnimationSet() { return animation_set; }
|
||||
|
||||
public func ControlUseStart(object clonk, int x, int y)
|
||||
{
|
||||
// Cut rope, or otherwise remove helper object.
|
||||
if (help)
|
||||
if (hook->Contained() != this)
|
||||
{
|
||||
var rope = help->GetRope();
|
||||
var rope = hook->GetRope();
|
||||
if (rope)
|
||||
rope->BreakRope();
|
||||
else
|
||||
help->RemoveObject();
|
||||
{
|
||||
rope->DrawIn();
|
||||
// rope->BreakRope();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -84,10 +101,9 @@ public func ControlUseStart(object clonk, int x, int y)
|
|||
// Start aiming
|
||||
fAiming = 1;
|
||||
|
||||
FinishedLoading(clonk);
|
||||
// PlayAnimation("Draw", 6, Anim_Linear(0, 0, GetAnimationLength("Draw"), animation_set["LoadTime"], ANIM_Hold), Anim_Const(1000));
|
||||
ControlUseHolding(clonk, x, y);
|
||||
|
||||
// clonk->StartLoad(this);
|
||||
FinishedLoading(clonk);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -127,8 +143,6 @@ public func FinishedAiming(object clonk, int angle)
|
|||
DetachMesh(hook_attach);
|
||||
hook_attach = nil;
|
||||
|
||||
// shoot
|
||||
// var hook = CreateObject(GrappleHook, 0, 0, NO_OWNER);
|
||||
hook->Exit();
|
||||
hook->Launch(angle, 100, clonk, this);
|
||||
DetachMesh(hook_attach);
|
||||
|
@ -136,7 +150,6 @@ public func FinishedAiming(object clonk, int angle)
|
|||
|
||||
// Open the hand to let the string go and play the fire animation
|
||||
PlayAnimation("Fire", 6, Anim_Linear(0, 0, GetAnimationLength("Fire"), animation_set["ShootTime"], ANIM_Hold), Anim_Const(1000));
|
||||
clonk->PlayAnimation("Close1Hand", 11, Anim_Const(0), Anim_Const(1000));
|
||||
clonk->StartShoot(this);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -5,12 +5,7 @@
|
|||
local master, index;
|
||||
local angle;
|
||||
|
||||
|
||||
public func SetAngle(int new_angle)
|
||||
{
|
||||
angle = new_angle;
|
||||
}
|
||||
|
||||
public func SetAngle(int new_angle) { angle = new_angle; }
|
||||
|
||||
public func SetMaster(new_master, new_index) { master = new_master; index = new_index; }
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
// length, length of segments, default 15
|
||||
*/
|
||||
|
||||
#include Library_Rope
|
||||
|
||||
static const Ladder_MaxParticles = 15;//30;//15*3;
|
||||
static const Ladder_Iterations = 10;
|
||||
static const Ladder_Precision = 100;
|
||||
|
@ -65,25 +67,6 @@ public func ControlUse(object clonk, int x, int y)
|
|||
return true;
|
||||
}
|
||||
|
||||
protected func AddSegment()
|
||||
{
|
||||
segments[ParticleCount] = CreateObject(Ropeladder_Segment);
|
||||
|
||||
segments[ParticleCount]->SetMaster(this, ParticleCount);
|
||||
|
||||
segments[ParticleCount]->SetNextLadder(segments[ParticleCount-1]);
|
||||
segments[ParticleCount-1]->SetPreviousLadder(segments[ParticleCount]);
|
||||
|
||||
segments[ParticleCount]->SetGraphics("None");
|
||||
|
||||
var oldx = particles[ParticleCount][0][0];
|
||||
var oldy = particles[ParticleCount][0][1];
|
||||
particles[ParticleCount] = [[ oldx+UnrollDir*Ladder_Precision, oldy], [ oldx, oldy], [0,1*Ladder_Precision], 1]; // Pos, Oldpos, acceleration (gravity), mass
|
||||
|
||||
ParticleCount++;
|
||||
UpdateSegmentOverlays();
|
||||
}
|
||||
|
||||
public func UpdateSegmentOverlays()
|
||||
{
|
||||
for(var i = 1; i < GetLength(segments); i++)
|
||||
|
@ -104,38 +87,6 @@ public func UpdateSegmentOverlays()
|
|||
}
|
||||
}
|
||||
|
||||
protected func RemoveSegment()
|
||||
{
|
||||
ParticleCount--;
|
||||
|
||||
segments[ParticleCount]->RemoveObject();
|
||||
|
||||
if(ParticleCount == 0)
|
||||
{
|
||||
RemoveEffect("IntHang", this);
|
||||
SetCategory(C4D_Object);
|
||||
SetAction("Idle");
|
||||
SetProperty("Collectible", 1);
|
||||
|
||||
// Try to move the Ropeladder somewhere out if it is stuck
|
||||
TestMoveOut( 0, -1); // Up
|
||||
TestMoveOut( 0, +1); // Down
|
||||
TestMoveOut(-1, 0); // Left
|
||||
TestMoveOut(+1, 0); // Right
|
||||
|
||||
grabber->RemoveObject();
|
||||
|
||||
SetGraphics("", GetID());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SetLength(segments, ParticleCount);
|
||||
SetLength(particles, ParticleCount);
|
||||
segments[ParticleCount-1]->SetPreviousLadder(nil);
|
||||
UpdateSegmentOverlays();
|
||||
}
|
||||
|
||||
func TestMoveOut(xdir, ydir)
|
||||
{
|
||||
if(!Stuck()) return;
|
||||
|
@ -213,32 +164,27 @@ public func Unroll(int dir, int unrolldir, int length)
|
|||
DoUnroll(dir);
|
||||
}
|
||||
|
||||
public func MakeBridge(obj1, obj2)
|
||||
{
|
||||
MirrorSegments = 1;
|
||||
SetProperty("Collectible", 0);
|
||||
StartRopeConnect(obj1, obj2);
|
||||
AddEffect("IntHang", this, 1, 1, this);
|
||||
}//MakeBridge(Object(221), Object(150))
|
||||
|
||||
protected func DoUnroll(dir)
|
||||
{
|
||||
MirrorSegments = dir;
|
||||
UnrollDir = dir;
|
||||
SetGraphics("Anchor");
|
||||
SetAction("Hanging");
|
||||
SetProperty("Collectible", 0);
|
||||
|
||||
TestArray = [[0, 1], [1, 0], [1, 1], [0, 2], [1, 2], [2, 0], [2, 1], [2, 2], [0, 3], [1, 3], [2, 3], [3, 0], [3, 1], [3, 2], [0, 4], [1, 4], [2, 4], [3, 3], [4, 0], [4, 1], [4, 2], [0, 5], [1, 5], [2, 5], [3, 4], [3, 5], [4, 3], [4, 4], [5, 0], [5, 1], [5, 2], [5, 3], [0, 6], [1, 6], [2, 6], [3, 6], [4, 5], [5, 4], [6, 0], [6, 1], [6, 2], [6, 3], [0, 7], [1, 7], [2, 7], [3, 7], [4, 6], [5, 5], [5, 6], [6, 4], [6, 5], [7, 0], [7, 1], [7, 2], [7, 3], [0, 8], [1, 8], [2, 8], [3, 8], [4, 7], [4, 8], [5, 7], [6, 6], [7, 4], [7, 5], [8, 0], [8, 1], [8, 2], [8, 3], [8, 4], [0, 9], [1, 9], [2, 9], [3, 9], [4, 9], [5, 8], [6, 7], [7, 6], [7, 7], [8, 5], [9, 0], [9, 1], [9, 2], [9, 3], [9, 4]];
|
||||
// TestArray = [[0, 1], [1, 0], [1, 1], [0, 2], [1, 2], [2, 0], [2, 1], [2, 2], [0, 3], [1, 3], [2, 3], [3, 0], [3, 1], [3, 2], [0, 4], [1, 4], [2, 4], [3, 3], [4, 0], [4, 1], [4, 2], [0, 5], [1, 5], [2, 5], [3, 4], [3, 5], [4, 3], [4, 4], [5, 0], [5, 1], [5, 2], [5, 3], [0, 6], [1, 6], [2, 6], [3, 6], [4, 5], [5, 4], [6, 0], [6, 1], [6, 2], [6, 3], [0, 7], [1, 7], [2, 7], [3, 7], [4, 6], [5, 5], [5, 6], [6, 4], [6, 5], [7, 0], [7, 1], [7, 2], [7, 3], [0, 8], [1, 8], [2, 8], [3, 8], [4, 7], [4, 8], [5, 7], [6, 6], [7, 4], [7, 5], [8, 0], [8, 1], [8, 2], [8, 3], [8, 4], [0, 9], [1, 9], [2, 9], [3, 9], [4, 9], [5, 8], [6, 7], [7, 6], [7, 7], [8, 5], [9, 0], [9, 1], [9, 2], [9, 3], [9, 4]];
|
||||
|
||||
grabber = CreateObject(Ropeladder_Grabber);
|
||||
grabber->SetAction("Attach", this);
|
||||
|
||||
ParticleCount = 1;
|
||||
|
||||
segments = CreateArray(ParticleCount);
|
||||
|
||||
segments[0] = CreateObject(Ropeladder_Segment);
|
||||
segments[0]->SetGraphics("None");
|
||||
|
||||
segments[0]->SetMaster(this, 0);
|
||||
|
||||
particles = CreateArray(ParticleCount);
|
||||
for(var i = 0; i < MaxSegmentCount; i++)
|
||||
particles[i] = [[ (GetX()+i*dir)*Ladder_Precision, GetY()*Ladder_Precision], [ (GetX()+i*1)*Ladder_Precision, GetY()*Ladder_Precision], [0,1*Ladder_Precision], 1]; // Pos, Oldpos, acceleration (gravity), mass
|
||||
particles[0] = [[ GetX()*Ladder_Precision, GetY()*Ladder_Precision], [(GetX()+1)*Ladder_Precision, GetY()*Ladder_Precision], [0,1*Ladder_Precision], 0];
|
||||
StartRope();
|
||||
|
||||
AddEffect("IntHang", this, 1, 1, this);
|
||||
|
||||
|
@ -257,7 +203,15 @@ func FxUnRollTimer()
|
|||
StartRollUp();
|
||||
return -1;
|
||||
}
|
||||
AddSegment();
|
||||
AddSegment(UnrollDir*Ladder_Precision, 0);
|
||||
}
|
||||
|
||||
func FxRollUpTimer() { if(ParticleCount == 0) return -1; RemoveSegment(); }
|
||||
|
||||
func FxIntHangTimer()
|
||||
{
|
||||
TimeStep();
|
||||
if(!Stuck()) TestLength();
|
||||
}
|
||||
|
||||
func TestLength()
|
||||
|
@ -268,32 +222,62 @@ func TestLength()
|
|||
StartRollUp();
|
||||
}
|
||||
|
||||
func FxRollUpTimer() { if(ParticleCount == 0) return -1; RemoveSegment(); }
|
||||
/* --------------------- Callbacks form the rope ---------------------- */
|
||||
|
||||
func FxIntHangTimer() { TimeStep(); }
|
||||
|
||||
// Verlet integration step
|
||||
func Verlet(fFirst)
|
||||
/* To be overloaded for special segment behaviour */
|
||||
private func CreateSegment(int index, object previous)
|
||||
{
|
||||
var fTimeStep = 1;
|
||||
for(var i = 1; i < ParticleCount; i++)
|
||||
var segment;
|
||||
if(index == 0)
|
||||
{
|
||||
var x = particles[i][0];
|
||||
var temp = x;
|
||||
var oldx = particles[i][1];
|
||||
var a = particles[i][2];
|
||||
|
||||
// Verlet step, get speed out of distance moved relativ to the last position
|
||||
particles[i][0][0] += x[0]-oldx[0]+a[0]*fTimeStep*fTimeStep;
|
||||
particles[i][0][1] += x[1]-oldx[1]+a[1]*fTimeStep*fTimeStep;
|
||||
particles[i][1] = temp;
|
||||
segment = CreateObject(Ropeladder_Segment);
|
||||
segment->SetGraphics("None");
|
||||
segment->SetMaster(this, 0);
|
||||
}
|
||||
particles[0][0] = [GetX()*Ladder_Precision, GetY()*Ladder_Precision];
|
||||
if(!Stuck()) TestLength();
|
||||
else
|
||||
{
|
||||
segment = CreateObject(Ropeladder_Segment);
|
||||
|
||||
segment->SetMaster(this, ParticleCount);
|
||||
|
||||
segment->SetNextLadder(previous);
|
||||
previous->SetPreviousLadder(segment);
|
||||
|
||||
segment->SetGraphics("None");
|
||||
}
|
||||
return segment;
|
||||
}
|
||||
|
||||
private func DeleteSegment(object segment, previous)
|
||||
{
|
||||
if(segment)
|
||||
segment->RemoveObject();
|
||||
if(previous)
|
||||
previous->SetPreviousLadder(nil);
|
||||
}
|
||||
|
||||
/* When the last segment is removed */
|
||||
private func RopeRemoved()
|
||||
{
|
||||
RemoveEffect("IntHang", this);
|
||||
SetCategory(C4D_Object);
|
||||
SetAction("Idle");
|
||||
SetProperty("Collectible", 1);
|
||||
|
||||
// Try to move the Ropeladder somewhere out if it is stuck
|
||||
TestMoveOut( 0, -1); // Up
|
||||
TestMoveOut( 0, +1); // Down
|
||||
TestMoveOut(-1, 0); // Left
|
||||
TestMoveOut(+1, 0); // Right
|
||||
|
||||
grabber->RemoveObject();
|
||||
|
||||
SetGraphics("", GetID());
|
||||
}
|
||||
|
||||
/* --------------------- Graphics of segments ---------------------- */
|
||||
func UpdateLines()
|
||||
{UpdateSegmentOverlays();
|
||||
{
|
||||
var fTimeStep = 1;
|
||||
var oldangle;
|
||||
for(var i=1; i < ParticleCount; i++)
|
||||
|
@ -423,22 +407,7 @@ func SetLineTransform(obj, int r, int xoff, int yoff, int length, int layer, int
|
|||
);
|
||||
}
|
||||
|
||||
func LogSpeed()
|
||||
{
|
||||
// Helperfunction for Debugpurpose
|
||||
var array = [];
|
||||
for(var i=0; i < ParticleCount; i++)
|
||||
{
|
||||
var x = particles[i][0];
|
||||
var oldx = particles[i][1];
|
||||
array[GetLength(array)] = Distance(x[0]-oldx[0], x[1]-oldx[1]);
|
||||
}
|
||||
Log("%v", array);
|
||||
}
|
||||
|
||||
func GetPartX(index) { return (particles[index][0][0]+Ladder_Precision/2)/Ladder_Precision; }
|
||||
func GetPartY(index) { return (particles[index][0][1]+Ladder_Precision/2)/Ladder_Precision; }
|
||||
|
||||
/* --------------------- Clonk on ladder ---------------------- */
|
||||
public func OnLadderGrab(clonk, index)
|
||||
{
|
||||
// Do some speed when the clonk jumps on the ladder
|
||||
|
@ -483,112 +452,6 @@ public func GetLadderData(index, &startx, &starty, &endx, &endy, &angle)
|
|||
return true;
|
||||
}
|
||||
|
||||
func SatisfyConstraints()
|
||||
{
|
||||
for(var j=0; j < Ladder_Iterations; j++)
|
||||
{
|
||||
// Satisfy all stick constraints (move the particles to fit the length)
|
||||
for(var i=0; i < ParticleCount-1; i++)
|
||||
{
|
||||
// Keep length
|
||||
var restlength = Ladder_SegmentLength*Ladder_Precision; // normal length between laddersegments
|
||||
// Get coordinates and inverse masses
|
||||
var x1 = particles[i][0];
|
||||
var x2 = particles[i+1][0];
|
||||
var invmass1 = particles[i][3];
|
||||
var invmass2 = particles[i+1][3];
|
||||
// calculate difference
|
||||
var delta = Vec_Sub(x2,x1);
|
||||
var deltalength = Sqrt(Vec_Dot(delta,delta));
|
||||
var diff = 0;
|
||||
if(deltalength != 0) // savety against division throught zero
|
||||
diff = (deltalength-restlength)*1000/(deltalength*(invmass1+invmass2));
|
||||
// Set new positions
|
||||
particles[i][0] = Vec_Add(x1, Vec_Div(Vec_Mul(delta, invmass1*diff), 1000));
|
||||
particles[i+1][0] = Vec_Sub(x2, Vec_Div(Vec_Mul(delta, invmass2*diff), 1000));
|
||||
}
|
||||
for(var i=0; i < ParticleCount; i++)
|
||||
{
|
||||
// Don't touch ground
|
||||
if(GBackSolid(GetPartX(i)-GetX(), GetPartY(i)-GetY()) )
|
||||
{
|
||||
// Moving left?
|
||||
var xdir = -1;
|
||||
if(particles[i][0][0] < particles[i][1][0])
|
||||
xdir = 1;
|
||||
var ydir = -1;
|
||||
// Moving up?
|
||||
if(particles[i][0][1] < particles[i][1][1])
|
||||
ydir = 1;
|
||||
// Look for all possible places where the particle could move (from nearest to farest)
|
||||
for(var pos in TestArray)
|
||||
{
|
||||
if(!GBackSolid(GetPartX(i)-GetX()+xdir*pos[0], GetPartY(i)-GetY()+ydir*pos[1]))
|
||||
{
|
||||
// Calculate the new position (if we don't move in a direction don't overwrite the old value)
|
||||
var new = [0,0];
|
||||
if(pos[0])
|
||||
new[0] = (GetPartX(i)+xdir*pos[0])*Ladder_Precision-xdir*Ladder_Precision/2;
|
||||
else
|
||||
new[0] = particles[i][0][0];
|
||||
if(pos[1])
|
||||
new[1] = (GetPartY(i)+ydir*pos[1])*Ladder_Precision-ydir*Ladder_Precision/2;
|
||||
else
|
||||
new[1] = particles[i][0][1];
|
||||
// Calculate the normalvector to apply the normal force accordingly
|
||||
var dif = Vec_Sub(new, particles[i][0]);
|
||||
var vel = Vec_Sub(particles[i][0], particles[i][1]);
|
||||
var tang = [dif[1], -dif[0]];
|
||||
var speed = Vec_Length(vel);
|
||||
var normalforce = Vec_Length(dif);
|
||||
// if the force is smaller then the speed decelerate
|
||||
if(normalforce < speed)
|
||||
{
|
||||
vel = Vec_Mul(vel, 1000-normalforce*1000/speed);
|
||||
vel = Vec_Div(vel, 1000);
|
||||
particles[i][1] = Vec_Sub(new, vel);
|
||||
}
|
||||
// If not stop instantly
|
||||
else
|
||||
particles[i][1] = new;
|
||||
particles[i][0] = new;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func LogArray()
|
||||
{
|
||||
// Helperfunction which has created "TestArray"
|
||||
var array = [];
|
||||
for(var dist = 1; dist < 10; dist++)
|
||||
for(var x = 0; x < 10; x++)
|
||||
for(var y = 0; y < 10; y++)
|
||||
{
|
||||
if(Distance(0,0,x,y) != dist) continue;
|
||||
array[GetLength(array)] = [x,y];
|
||||
}
|
||||
Log("%v", array);
|
||||
}
|
||||
|
||||
func TimeStep() {
|
||||
Verlet();
|
||||
SatisfyConstraints();
|
||||
UpdateLines();
|
||||
}
|
||||
|
||||
// Some vector math
|
||||
func Vec_Sub(array x, array y) { return [x[0]-y[0], x[1]-y[1]]; }
|
||||
func Vec_Add(array x, array y) { return [x[0]+y[0], x[1]+y[1]]; }
|
||||
func Vec_Mul(array x, int i) { return [x[0]*i, x[1]*i]; }
|
||||
func Vec_Div(array x, int i) { return [x[0]/i, x[1]/i]; }
|
||||
func Vec_Dot(array x, array y) { return x[0]*y[0]+x[1]*y[1]; }
|
||||
func Vec_Length(array x) { return Sqrt(x[0]*x[0]+x[1]*x[1]); }
|
||||
func Vec_Angle(array x, array y) { return Angle(x[0], x[1], y[0], y[1]); }
|
||||
|
||||
func Definition(def) {
|
||||
SetProperty("ActMap", {
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
[DefCore]
|
||||
id=Library_Rope
|
||||
Version=4,10,0,0
|
||||
Category=C4D_StaticBack
|
Binary file not shown.
After Width: | Height: | Size: 154 B |
|
@ -0,0 +1,513 @@
|
|||
/*--
|
||||
Rope control
|
||||
Authors: Randrian
|
||||
|
||||
Containes the basic functionality for ladders.
|
||||
--*/
|
||||
|
||||
static const Rope_MaxParticles = 15;//30;//15*3;
|
||||
static const Rope_Iterations = 10;
|
||||
static const Rope_Precision = 100;
|
||||
static const Rope_SegmentLength = 5;//2;
|
||||
|
||||
local particles;
|
||||
local segments;
|
||||
local TestArray;
|
||||
local ParticleCount;
|
||||
|
||||
local objects;
|
||||
local length;
|
||||
|
||||
local length_auto;
|
||||
|
||||
local Max_Length;
|
||||
|
||||
protected func StartRope()
|
||||
{
|
||||
objects = [[this, 0], [nil, nil]];
|
||||
TestArray = [[0, 1], [1, 0], [1, 1], [0, 2], [1, 2], [2, 0], [2, 1], [2, 2], [0, 3], [1, 3], [2, 3], [3, 0], [3, 1], [3, 2], [0, 4], [1, 4], [2, 4], [3, 3], [4, 0], [4, 1], [4, 2], [0, 5], [1, 5], [2, 5], [3, 4], [3, 5], [4, 3], [4, 4], [5, 0], [5, 1], [5, 2], [5, 3], [0, 6], [1, 6], [2, 6], [3, 6], [4, 5], [5, 4], [6, 0], [6, 1], [6, 2], [6, 3], [0, 7], [1, 7], [2, 7], [3, 7], [4, 6], [5, 5], [5, 6], [6, 4], [6, 5], [7, 0], [7, 1], [7, 2], [7, 3], [0, 8], [1, 8], [2, 8], [3, 8], [4, 7], [4, 8], [5, 7], [6, 6], [7, 4], [7, 5], [8, 0], [8, 1], [8, 2], [8, 3], [8, 4], [0, 9], [1, 9], [2, 9], [3, 9], [4, 9], [5, 8], [6, 7], [7, 6], [7, 7], [8, 5], [9, 0], [9, 1], [9, 2], [9, 3], [9, 4]];
|
||||
|
||||
length = Rope_SegmentLength;
|
||||
|
||||
ParticleCount = 1;
|
||||
segments = CreateArray(ParticleCount);
|
||||
segments[0] = CreateSegment(0, nil);
|
||||
|
||||
particles = CreateArray(ParticleCount);
|
||||
particles[0] = [[ GetX()*Rope_Precision, GetY()*Rope_Precision], [(GetX()+1)*Rope_Precision, GetY()*Rope_Precision], [0,1*Rope_Precision], 0];
|
||||
}
|
||||
|
||||
public func StartRopeConnect(object obj1, object obj2)
|
||||
{
|
||||
length = ObjectDistance(obj1, obj2);
|
||||
objects = [[obj1, 0], [obj2, 1]];
|
||||
|
||||
TestArray = [[0, 1], [1, 0], [1, 1], [0, 2], [1, 2], [2, 0], [2, 1], [2, 2], [0, 3], [1, 3], [2, 3], [3, 0], [3, 1], [3, 2], [0, 4], [1, 4], [2, 4], [3, 3], [4, 0], [4, 1], [4, 2], [0, 5], [1, 5], [2, 5], [3, 4], [3, 5], [4, 3], [4, 4], [5, 0], [5, 1], [5, 2], [5, 3], [0, 6], [1, 6], [2, 6], [3, 6], [4, 5], [5, 4], [6, 0], [6, 1], [6, 2], [6, 3], [0, 7], [1, 7], [2, 7], [3, 7], [4, 6], [5, 5], [5, 6], [6, 4], [6, 5], [7, 0], [7, 1], [7, 2], [7, 3], [0, 8], [1, 8], [2, 8], [3, 8], [4, 7], [4, 8], [5, 7], [6, 6], [7, 4], [7, 5], [8, 0], [8, 1], [8, 2], [8, 3], [8, 4], [0, 9], [1, 9], [2, 9], [3, 9], [4, 9], [5, 8], [6, 7], [7, 6], [7, 7], [8, 5], [9, 0], [9, 1], [9, 2], [9, 3], [9, 4]];
|
||||
|
||||
ParticleCount = length/Rope_SegmentLength;
|
||||
|
||||
var yoff = 0;
|
||||
if(ParticleCount < 2)
|
||||
{
|
||||
ParticleCount = 2;
|
||||
yoff = 1;
|
||||
length = 10;
|
||||
}
|
||||
|
||||
segments = CreateArray(ParticleCount);
|
||||
for(var i = 0; i < ParticleCount; i++)
|
||||
{
|
||||
var prev = nil;
|
||||
if(i > 0) prev = segments[i-1];
|
||||
segments[i] = CreateSegment(i, prev);
|
||||
}
|
||||
|
||||
particles = CreateArray(ParticleCount);
|
||||
var x, y;
|
||||
for(var i = 0; i < ParticleCount; i++)
|
||||
{
|
||||
x = obj1->GetX(Rope_Precision)*(ParticleCount-i)/ParticleCount+obj2->GetX(Rope_Precision)*i/ParticleCount;
|
||||
y = obj1->GetY(Rope_Precision)*(ParticleCount-i)/ParticleCount+obj2->GetY(Rope_Precision)*i/ParticleCount;
|
||||
y += yoff*i;
|
||||
particles[i] = [[ x, y], [ x, y], [0,1*Rope_Precision], 1]; // Pos, Oldpos, acceleration (gravity), mass
|
||||
}
|
||||
particles[0][2] = [0,0];
|
||||
particles[0][3] = 0;
|
||||
particles[-1][2] = [0,0];
|
||||
particles[-1][3] = 1;
|
||||
|
||||
ConnectLoose();
|
||||
|
||||
UpdateSegmentOverlays();
|
||||
TimeStep();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
protected func Destruction()
|
||||
{
|
||||
RemoveRope();
|
||||
}
|
||||
|
||||
public func RemoveRope()
|
||||
{
|
||||
if(segments)
|
||||
for(var segment in segments)
|
||||
DeleteSegment(segment);
|
||||
}
|
||||
|
||||
public func SetFixed(bool fixed_1, bool fixed_2)
|
||||
{
|
||||
objects[0][1] = !fixed_1;
|
||||
objects[1][1] = !fixed_2;
|
||||
particles[ 0][3] = objects[0][1];
|
||||
particles[-1][3] = objects[1][1];
|
||||
}
|
||||
|
||||
func ConnectLoose()
|
||||
{
|
||||
length_auto = 1;
|
||||
}
|
||||
|
||||
func ConnectPull()
|
||||
{
|
||||
length_auto = 0;
|
||||
}
|
||||
|
||||
/* To be overloaded for special segment behaviour */
|
||||
private func CreateSegment(int index, object previous) { }
|
||||
|
||||
private func DeleteSegment(object segment, previous)
|
||||
{
|
||||
if(segment)
|
||||
segment->RemoveObject();
|
||||
}
|
||||
|
||||
/* When the last segment is removed */
|
||||
private func RopeRemoved() { }
|
||||
|
||||
/* Adding and removing segments */
|
||||
public func AddSegment(int xoffset, int yoffset)
|
||||
{
|
||||
segments[ParticleCount] = CreateSegment(ParticleCount, segments[ParticleCount-1]);
|
||||
|
||||
var oldx = particles[ParticleCount-1][0][0];
|
||||
var oldy = particles[ParticleCount-1][0][1];
|
||||
particles[ParticleCount] = [[ oldx+xoffset, oldy+yoffset], [ oldx, oldy], [0,1*Rope_Precision], 1]; // Pos, Oldpos, acceleration (gravity), mass
|
||||
|
||||
ParticleCount++;
|
||||
|
||||
length += Rope_SegmentLength;
|
||||
|
||||
UpdateSegmentOverlays();
|
||||
}
|
||||
|
||||
public func PickSegment(int index) // Removes a segment form the middle
|
||||
{
|
||||
if(index >= ParticleCount-1) return RemoveSegment();
|
||||
|
||||
var previous = nil;
|
||||
if(index > 0) previous = segments[index-1];
|
||||
DeleteSegment(segments[index], previous);
|
||||
|
||||
for(var i = index; i < ParticleCount-1; i++)
|
||||
{
|
||||
segments[i] = segments[i+1];
|
||||
particles[i] = particles[i+1];
|
||||
}
|
||||
ParticleCount--;
|
||||
|
||||
SetLength(segments, ParticleCount);
|
||||
SetLength(particles, ParticleCount);
|
||||
UpdateSegmentOverlays();
|
||||
}
|
||||
|
||||
public func RemoveSegment(fNoLengthAdjust)
|
||||
{
|
||||
ParticleCount--;
|
||||
|
||||
var previous = nil;
|
||||
if(ParticleCount-1 >= 0) previous = segments[ParticleCount-1];
|
||||
DeleteSegment(segments[ParticleCount], previous);
|
||||
|
||||
if(ParticleCount == 0)
|
||||
{
|
||||
RopeRemoved();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!fNoLengthAdjust)
|
||||
length -= Rope_SegmentLength;
|
||||
|
||||
SetLength(segments, ParticleCount);
|
||||
SetLength(particles, ParticleCount);
|
||||
UpdateSegmentOverlays();
|
||||
}
|
||||
|
||||
public func MaxLengthReached() { }
|
||||
|
||||
public func DoLength(int dolength)
|
||||
{
|
||||
length += dolength;
|
||||
if(Max_Length)
|
||||
if(length > Max_Length)
|
||||
{
|
||||
MaxLengthReached();
|
||||
length = Max_Length;
|
||||
}
|
||||
if(length < Rope_SegmentLength*2) length = Rope_SegmentLength*2;
|
||||
|
||||
var last_length = GetLastLength();
|
||||
// Remove Points
|
||||
while( last_length < Rope_SegmentLength*Rope_Precision/2 && ParticleCount > 2)
|
||||
{
|
||||
particles[ParticleCount-2] = particles[ParticleCount-1];
|
||||
RemoveSegment(1);
|
||||
|
||||
last_length = GetLastLength();
|
||||
}
|
||||
var i = 0;
|
||||
while( last_length > Rope_SegmentLength*Rope_Precision*3/2)
|
||||
{
|
||||
ParticleCount++;
|
||||
SetLength(particles, ParticleCount);
|
||||
var x2 = particles[ParticleCount-2][0][0];
|
||||
var y2 = particles[ParticleCount-2][0][1];
|
||||
|
||||
var x4 = particles[ParticleCount-2][1][0];
|
||||
var y4 = particles[ParticleCount-2][1][1];
|
||||
particles[-1] = [[0,0], [0,0], [0,0], 0];
|
||||
particles[-1] = [[x2, y2], [x4, y4], [0,2*Rope_Precision], 1];
|
||||
|
||||
for(var i = ParticleCount-2; i > 0; i--)
|
||||
{
|
||||
var x = particles[i-1][0][0];
|
||||
var y = particles[i-1][0][1];
|
||||
var x2 = particles[i][0][0];
|
||||
var y2 = particles[i][0][1];
|
||||
|
||||
var x3 = particles[i-1][1][0];
|
||||
var y3 = particles[i-1][1][1];
|
||||
var x4 = particles[i][1][0];
|
||||
var y4 = particles[i][1][1];
|
||||
|
||||
particles[i] = [[ x/ParticleCount +x2*(ParticleCount-1)/ParticleCount, y/ParticleCount +y2*(ParticleCount-1)/ParticleCount],
|
||||
[ x3/ParticleCount+x4*(ParticleCount-1)/ParticleCount, y3/ParticleCount+y4*(ParticleCount-1)/ParticleCount], [0,1*Rope_Precision], 1];
|
||||
}
|
||||
SetLength(segments, ParticleCount);
|
||||
segments[ParticleCount-1] = CreateSegment(ParticleCount, segments[ParticleCount-2]);
|
||||
|
||||
last_length = GetLastLength();
|
||||
}
|
||||
UpdateLines();
|
||||
particles[ 0][3] = objects[0][1];
|
||||
particles[-1][3] = objects[1][1];
|
||||
return;
|
||||
}
|
||||
|
||||
func GetLastLength()
|
||||
{
|
||||
return length*Rope_Precision-Rope_SegmentLength*Rope_Precision*(ParticleCount-1);
|
||||
}
|
||||
|
||||
/* for the graphics appeareance should be overloaded */
|
||||
private func UpdateSegmentOverlays() { }
|
||||
private func UpdateLines() {}
|
||||
|
||||
/* The procedure of a time step, this should be called with a timercall or an effect! */
|
||||
public func TimeStep()
|
||||
{
|
||||
if(length_auto) AccumulateForces();
|
||||
Verlet();
|
||||
SatisfyConstraints();
|
||||
ForcesOnObjects();
|
||||
UpdateLines();
|
||||
}
|
||||
|
||||
func AccumulateForces()
|
||||
{
|
||||
for(var i = 1; i < ParticleCount; i++)
|
||||
{
|
||||
var fx = 0, fy = 0, angle;
|
||||
if(i < ParticleCount-2 && length_auto)
|
||||
{
|
||||
angle = Angle(particles[i][0][0], particles[i][0][1], particles[i+1][0][0], particles[i+1][0][1]);
|
||||
fx = Sin(angle, 5*Rope_Precision);
|
||||
fy =-Cos(angle, 5*Rope_Precision);
|
||||
/* angle = Angle(particles[i-1][0][0], particles[i-1][0][1], particles[i+1][0][0], particles[i+1][0][1]);
|
||||
var middle = Vec_Div(Vec_Add(particles[i-1][0], particles[i+1][0]), 1);
|
||||
var diff = Vec_Sub(middle, particles[i][0]);
|
||||
var length = Vec_Length(diff);
|
||||
fx = Sin(angle, length/2);
|
||||
fy =-Cos(angle, length/2);*/
|
||||
}
|
||||
particles[i][2] = [fx,fy+1*Rope_Precision];
|
||||
}
|
||||
}
|
||||
|
||||
// Verlet integration step
|
||||
private func Verlet(fFirst)
|
||||
{
|
||||
var fTimeStep = 1;
|
||||
|
||||
// Copy Position of the objects
|
||||
var j = 0;
|
||||
for(var i = 0; i < 2; i++ || j--)
|
||||
{
|
||||
if(objects[i][1] == 0)
|
||||
SetParticleToObject(j, i);
|
||||
}
|
||||
|
||||
// Verlet
|
||||
for(var i = 1; i < ParticleCount; i++)
|
||||
{
|
||||
var x = particles[i][0];
|
||||
var temp = x;
|
||||
var oldx = particles[i][1];
|
||||
var a = particles[i][2];
|
||||
|
||||
// Verlet step, get speed out of distance moved relativ to the last position
|
||||
particles[i][0][0] += x[0]-oldx[0]+a[0]*fTimeStep*fTimeStep;
|
||||
particles[i][0][1] += x[1]-oldx[1]+a[1]*fTimeStep*fTimeStep;
|
||||
particles[i][1] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
public func SetParticleToObject(int index, int obj_index)
|
||||
{
|
||||
var obj = objects[obj_index][0];
|
||||
if(obj == nil) return;
|
||||
|
||||
if(obj->Contained()) obj = obj->Contained();
|
||||
particles[index][0][0] = obj->GetX(Rope_Precision);
|
||||
particles[index][0][1] = obj->GetY(Rope_Precision);
|
||||
|
||||
particles[index][1][0] = particles[index][0][0];
|
||||
particles[index][1][1] = particles[index][0][1];
|
||||
particles[index][1][0] = obj->GetX(Rope_Precision);
|
||||
particles[index][1][1] = obj->GetY(Rope_Precision);
|
||||
}
|
||||
|
||||
private func SatisfyConstraints()
|
||||
{
|
||||
var segment_pick = nil;
|
||||
for(var j=0; j < Rope_Iterations; j++)
|
||||
{
|
||||
if(length_auto)
|
||||
{
|
||||
// Copy Position of the objects
|
||||
for(var i = 0, i2 = 0; i < 2; i++ || i2--)
|
||||
SetParticleToObject(i2, i);
|
||||
}
|
||||
|
||||
// Satisfy all stick constraints (move the particles to fit the length)
|
||||
for(var i=0; i < ParticleCount-1; i++)
|
||||
{
|
||||
// Keep length
|
||||
var restlength = Rope_SegmentLength*Rope_Precision; // normal length between two points
|
||||
//var restlength = Rope_PointDistance*Rope_Precision; // normal length between laddersegments
|
||||
if(i == ParticleCount-2)
|
||||
{
|
||||
restlength = GetLastLength();
|
||||
}
|
||||
// Get coordinates and inverse masses
|
||||
var x1 = particles[i][0];
|
||||
var x2 = particles[i+1][0];
|
||||
var invmass1 = particles[i][3];
|
||||
var invmass2 = particles[i+1][3];
|
||||
// calculate difference
|
||||
var delta = Vec_Sub(x2,x1);
|
||||
var deltalength = Sqrt(Vec_Dot(delta,delta));
|
||||
if(deltalength < restlength)
|
||||
{
|
||||
if(deltalength < restlength*3/4 && length_auto && i < ParticleCount-3)
|
||||
segment_pick = i;
|
||||
continue;
|
||||
}
|
||||
var diff = 0;
|
||||
if(deltalength != 0) // savety against division throught zero
|
||||
diff = (deltalength-restlength)*1000/(deltalength*(invmass1+invmass2));
|
||||
// Set new positions
|
||||
particles[i][0] = Vec_Add(x1, Vec_Div(Vec_Mul(delta, invmass1*diff), 1000));
|
||||
particles[i+1][0] = Vec_Sub(x2, Vec_Div(Vec_Mul(delta, invmass2*diff), 1000));
|
||||
}
|
||||
if(segment_pick != nil)
|
||||
;//PickSegment(segment_pick);
|
||||
for(var i=0; i < ParticleCount; i++)
|
||||
{
|
||||
// Don't touch ground
|
||||
if(GBackSolid(GetPartX(i)-GetX(), GetPartY(i)-GetY()) )
|
||||
{
|
||||
// Moving left?
|
||||
var xdir = -1;
|
||||
if(particles[i][0][0] < particles[i][1][0])
|
||||
xdir = 1;
|
||||
var ydir = -1;
|
||||
// Moving up?
|
||||
if(particles[i][0][1] < particles[i][1][1])
|
||||
ydir = 1;
|
||||
// Look for all possible places where the particle could move (from nearest to farest)
|
||||
for(var pos in TestArray)
|
||||
{
|
||||
if(!GBackSolid(GetPartX(i)-GetX()+xdir*pos[0], GetPartY(i)-GetY()+ydir*pos[1]))
|
||||
{
|
||||
// Calculate the new position (if we don't move in a direction don't overwrite the old value)
|
||||
var new = [0,0];
|
||||
if(pos[0])
|
||||
new[0] = (GetPartX(i)+xdir*pos[0])*Rope_Precision-xdir*Rope_Precision/2;
|
||||
else
|
||||
new[0] = particles[i][0][0];
|
||||
if(pos[1])
|
||||
new[1] = (GetPartY(i)+ydir*pos[1])*Rope_Precision-ydir*Rope_Precision/2;
|
||||
else
|
||||
new[1] = particles[i][0][1];
|
||||
// Calculate the normalvector to apply the normal force accordingly
|
||||
var dif = Vec_Sub(new, particles[i][0]);
|
||||
var vel = Vec_Sub(particles[i][0], particles[i][1]);
|
||||
var tang = [dif[1], -dif[0]];
|
||||
var speed = Vec_Length(vel);
|
||||
var normalforce = Vec_Length(dif);
|
||||
// if the force is smaller then the speed decelerate
|
||||
if(normalforce < speed)
|
||||
{
|
||||
vel = Vec_Mul(vel, 1000-normalforce*1000/speed);
|
||||
vel = Vec_Div(vel, 1000);
|
||||
particles[i][1] = Vec_Sub(new, vel);
|
||||
}
|
||||
// If not stop instantly
|
||||
else
|
||||
particles[i][1] = new;
|
||||
particles[i][0] = new;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetLineLength()
|
||||
{
|
||||
var length_vertex = 0;
|
||||
for(var i=1; i < ParticleCount; i++)
|
||||
length_vertex += Distance(particles[i][0][0], particles[i][0][1], particles[i-1][0][0], particles[i-1][0][1]);
|
||||
return length_vertex;
|
||||
}
|
||||
|
||||
func ForcesOnObjects()
|
||||
{
|
||||
if(!length) return;
|
||||
var length_vertex = 0;
|
||||
var redo = 5;
|
||||
for(var i=1; i < ParticleCount; i++)
|
||||
length_vertex += Distance(particles[i][0][0], particles[i][0][1], particles[i-1][0][0], particles[i-1][0][1]);
|
||||
|
||||
while( length_auto && redo)
|
||||
{
|
||||
var speed = Vec_Length(Vec_Sub(particles[-1][0], particles[-1][1]));
|
||||
if(speed > 150) DoLength(1);
|
||||
else if(speed < 50) DoLength(-1);
|
||||
else redo = 0;
|
||||
if(redo) redo --;
|
||||
particles[-1][3] = 1;
|
||||
SatisfyConstraints();
|
||||
}
|
||||
var j = 0;
|
||||
if(!length_auto || length == Max_Length)
|
||||
for(var i = 0; i < 2; i++)
|
||||
{
|
||||
if(i == 1) j = ParticleCount-1;
|
||||
var obj = objects[i][0];
|
||||
if(obj == nil || objects[i][1] == 0) continue;
|
||||
if(obj->Contained()) obj = obj->Contained();
|
||||
var speed = obj->GetXDir(Rope_Precision);
|
||||
var x = obj->GetX(Rope_Precision), y = obj->GetY(Rope_Precision);
|
||||
obj->SetPosition(particles[j][0][0], particles[j][0][1], 1, Rope_Precision);
|
||||
if(obj->Stuck())
|
||||
obj->SetPosition(x, y, 1, Rope_Precision);
|
||||
|
||||
obj->SetXDir( particles[j][0][0]-particles[j][1][0], Rope_Precision);
|
||||
obj->SetYDir( particles[j][0][1]-particles[j][1][1], Rope_Precision);
|
||||
}
|
||||
}
|
||||
|
||||
/* Helperstuff */
|
||||
private func LogArray()
|
||||
{
|
||||
// Helperfunction which has created "TestArray"
|
||||
var array = [];
|
||||
for(var dist = 1; dist < 10; dist++)
|
||||
for(var x = 0; x < 10; x++)
|
||||
for(var y = 0; y < 10; y++)
|
||||
{
|
||||
if(Distance(0,0,x,y) != dist) continue;
|
||||
array[GetLength(array)] = [x,y];
|
||||
}
|
||||
Log("%v", array);
|
||||
}
|
||||
|
||||
func LogSpeed()
|
||||
{
|
||||
// Helperfunction for Debugpurpose
|
||||
var array = [];
|
||||
for(var i=0; i < ParticleCount; i++)
|
||||
{
|
||||
var x = particles[i][0];
|
||||
var oldx = particles[i][1];
|
||||
array[GetLength(array)] = Distance(x[0]-oldx[0], x[1]-oldx[1]);
|
||||
}
|
||||
Log("%v", array);
|
||||
}
|
||||
|
||||
// Some vector math
|
||||
func Vec_Sub(array x, array y) { return [x[0]-y[0], x[1]-y[1]]; }
|
||||
func Vec_Add(array x, array y) { return [x[0]+y[0], x[1]+y[1]]; }
|
||||
func Vec_Mul(array x, int i) { return [x[0]*i, x[1]*i]; }
|
||||
func Vec_Div(array x, int i) { return [x[0]/i, x[1]/i]; }
|
||||
func Vec_Dot(array x, array y) { return x[0]*y[0]+x[1]*y[1]; }
|
||||
func Vec_Length(array x) { return Sqrt(x[0]*x[0]+x[1]*x[1]); }
|
||||
func Vec_Angle(array x, array y) { return Angle(x[0], x[1], y[0], y[1]); }
|
||||
func Vec_Normalize(array x, int precision) { return Vec_Div(Vec_Mul(x, precision), Vec_Length(x)); }
|
||||
|
||||
func GetPartX(index) { return (particles[index][0][0]+Rope_Precision/2)/Rope_Precision; }
|
||||
func GetPartY(index) { return (particles[index][0][1]+Rope_Precision/2)/Rope_Precision; }
|
|
@ -2,9 +2,13 @@
|
|||
|
||||
func Initialize()
|
||||
{
|
||||
CreateObject(Ropeladder, 174, 445)->Unroll(-1);
|
||||
// CreateObject(Ropeladder, 174, 445)->Unroll(-1, 0, 25);
|
||||
CreateObject(Ropeladder, 328, 564);
|
||||
CreateObject(Ropeladder, 226, 330);
|
||||
|
||||
var Rock1 = CreateObject(Rock, 159, 363);
|
||||
var Rock2 = CreateObject(Rock, 232, 388);
|
||||
// CreateObject(Ropeladder, 197, 432)->MakeBridge(Rock1, Rock2);
|
||||
}
|
||||
|
||||
func InitializePlayer(int iPlr, int iX, int iY, object pBase, int iTeam)
|
||||
|
@ -27,11 +31,11 @@ func Initialize()
|
|||
var clonk = GetCrew(iPlr);
|
||||
clonk->DoEnergy(100000);
|
||||
clonk->SetPosition(50, 490);
|
||||
clonk->CreateContents(Musket);
|
||||
clonk->CreateContents(LeadShot);
|
||||
// clonk->CreateContents(Musket);
|
||||
// clonk->CreateContents(LeadShot);
|
||||
// clonk->CreateContents(Javelin);
|
||||
// clonk->CreateContents(DynamiteBox);
|
||||
// clonk->CreateContents(GrappleBow);
|
||||
clonk->CreateContents(GrappleBow);
|
||||
// clonk->CreateContents(Bow);
|
||||
// clonk->Collect(CreateObject(Arrow));
|
||||
return;
|
||||
|
|
|
@ -511,6 +511,13 @@ void C4Object::ForcePosition(int32_t tx, int32_t ty)
|
|||
UpdateSolidMask(false);
|
||||
}
|
||||
|
||||
void C4Object::ForcePosition(int32_t tx, int32_t ty, long iPrec)
|
||||
{
|
||||
fix_x=itofix(tx, iPrec); fix_y=itofix(ty, iPrec);
|
||||
UpdatePos();
|
||||
UpdateSolidMask(false);
|
||||
}
|
||||
|
||||
void C4Object::MovePosition(int32_t dx, int32_t dy)
|
||||
{
|
||||
// move object position; repositions SolidMask
|
||||
|
|
|
@ -306,6 +306,7 @@ public:
|
|||
bool Exit(int32_t iX=0, int32_t iY=0, int32_t iR=0, C4Real iXDir=Fix0, C4Real iYDir=Fix0, C4Real iRDir=Fix0, bool fCalls=true);
|
||||
void CopyMotion(C4Object *from);
|
||||
void ForcePosition(int32_t tx, int32_t ty);
|
||||
void ForcePosition(int32_t tx, int32_t ty, long iPrec);
|
||||
void MovePosition(int32_t dx, int32_t dy);
|
||||
void DoMotion(int32_t mx, int32_t my);
|
||||
bool ActivateEntrance(int32_t by_plr, C4Object *by_obj);
|
||||
|
|
|
@ -470,16 +470,17 @@ static C4Void FnRemoveObject(C4AulObjectContext *cthr, bool fEjectContents)
|
|||
return C4VNull;
|
||||
}
|
||||
|
||||
static C4Void FnSetPosition(C4AulObjectContext *cthr, long iX, long iY, bool fCheckBounds)
|
||||
static C4Void FnSetPosition(C4AulObjectContext *cthr, long iX, long iY, bool fCheckBounds, long iPrec)
|
||||
{
|
||||
if (!iPrec) iPrec = 1;
|
||||
if (fCheckBounds)
|
||||
{
|
||||
// BoundsCheck takes ref to C4Real and not to long
|
||||
C4Real i_x = itofix(iX), i_y = itofix(iY);
|
||||
C4Real i_x = itofix(iX, iPrec), i_y = itofix(iY, iPrec);
|
||||
cthr->Obj->BoundsCheck(i_x, i_y);
|
||||
iX = fixtoi(i_x); iY = fixtoi(i_y);
|
||||
iX = fixtoi(i_x, iPrec); iY = fixtoi(i_y, iPrec);
|
||||
}
|
||||
cthr->Obj->ForcePosition(iX,iY);
|
||||
cthr->Obj->ForcePosition(iX,iY, iPrec);
|
||||
// update liquid
|
||||
cthr->Obj->UpdateInLiquid();
|
||||
return C4VNull;
|
||||
|
@ -1205,10 +1206,11 @@ static long FnGetComDir(C4AulObjectContext *cthr)
|
|||
return cthr->Obj->Action.ComDir;
|
||||
}
|
||||
|
||||
static Nillable<long> FnGetX(C4AulContext *cthr)
|
||||
static Nillable<long> FnGetX(C4AulContext *cthr, long iPrec)
|
||||
{
|
||||
if (!cthr->Obj) return C4VNull;
|
||||
return cthr->Obj->GetX();
|
||||
if (!iPrec) iPrec = 1;
|
||||
return fixtoi(cthr->Obj->fix_x, iPrec);
|
||||
}
|
||||
|
||||
static long FnGetVertexNum(C4AulObjectContext *cthr)
|
||||
|
@ -1299,10 +1301,11 @@ static C4Void FnSetContactDensity(C4AulObjectContext *cthr, long iDensity)
|
|||
return C4VNull;
|
||||
}
|
||||
|
||||
static Nillable<long> FnGetY(C4AulContext *cthr)
|
||||
static Nillable<long> FnGetY(C4AulContext *cthr, long iPrec)
|
||||
{
|
||||
if (!cthr->Obj) return C4VNull;
|
||||
return cthr->Obj->GetY();
|
||||
if (!iPrec) iPrec = 1;
|
||||
return fixtoi(cthr->Obj->fix_y, iPrec);
|
||||
}
|
||||
|
||||
static bool FnGetAlive(C4AulObjectContext *cthr)
|
||||
|
|
Loading…
Reference in New Issue