Cocos2dx 3d open source project fantasyWarrior3D starts from and ends [AttackManager & GameMaster] And cocos2dx open source games
[AttackCommand] 1. Declare the basic collision body as the attack unit released by the role
BasicCollider = class ("BasicCollider", function ()
local node = cc.Node: create ()
node: setCascadeColorEnabled (true)
return node
end)
function BasicCollider: ctor ()
self.minRange = 0 --the min radius of the fan
self.maxRange = 150 --the max radius of the fan
self.angle = 120 --arc of attack, in radians
self.knock = 150 --default knock, knocks 150 units
self.mask = 1 --1 is Heroes, 2 is enemy, 3 ??
self.damage = 100
self.facing = 0 --this is radians
self.duration = 0
self.curDuration = 0
self.speed = 0 --traveling speed}
self.criticalChance = 0
end
The specific parameters of each role are configured in GlobalVariables.lua
angle Attack angle, very useful, related to skills and the scope of attack
MaxRange attack scope
These two parameters can determine a "skill application area", which can be easily realized such as "fan-shaped" attack area
In this way, the attack skills do not necessarily need to be triggered by BasicCollider colliding with the target, as long as the enemy is in the attack area, it can be considered hit.
speed The speed at which the attacking body moves. For the attack of a warrior or the "ice wall" of a mage, the speed is 0
duration
DOTTimer continuous damage cd
You can also add an attribute maxTarget to determine whether a skill can be absorbed by a single body or can penetrate a target.
Act on multiple targets. For example, in Dota, Daniel "Shockwave" Lich "Serial Frost", etc.
2. AttackManager All released attack units are placed in AttackManager
solveAttacks attack unit frame loop
There are 3 main things done:
[1] Determine whether "hit"
The onCollide attack takes effect: the condition is that the distance and angle are satisfied
_myPos will keep updating with the game
function Actor: baseUpdate (dt)
self._myPos = getPosTable (self)
...
end
Calculate the angle required for the attack unit to turn to the target
local angle = radNormalize (cc.pToAngleSelf (cc.pSub (mpos, apos)))
Calculate the direction of the attacking unit
local afacing = radNormalize (attack.facing)
Determine if you are in the attack zone
if (afacing + attack.angle / 2)> angle and angle> (afacing- attack.angle / 2) then
attack: onCollide (monster)
end
[2] Judge timeout according to duration
onTimeOut remove attack unit
[3] Update location according to speed
onUpdate
3. Inherit the basic attack units to achieve various character skills. Then take a look at how the mage's "ice wall" does
Mage: specialAttack ()
among them
local pos1 = getPosTable (self)
local pos2 = getPosTable (self)
local pos3 = getPosTable (self)
pos1.x = pos1.x + 130
pos2.x = pos2.x + 330
pos3.x = pos3.x + 530
pos1 = cc.pRotateByAngle (pos1, self._myPos, self._curFacing)
pos2 = cc.pRotateByAngle (pos2, self._myPos, self._curFacing)
pos3 = cc.pRotateByAngle (pos3, self._myPos, self._curFacing)
pRotateByAngle returns the point to pos1 with self._myPos as the rotation axis, and rotates self._curFacing in a counterclockwise direction,
In this way, three points are finally obtained. They are 130 330 530 from the mage on the line between the mage and the target. Created 3 MageIceSpikes at these 3 points
MageIceSpikes.create
Randomly consist of 10 ice spikes, and add particle effects
Attributes:
_specialAttack = {
minRange = 0,
maxRange = 140,
angle = DEGREES_TO_RADIANS (360),
knock = 75,
damage = 250,
mask = EnumRaceType.HERO,
duration = 4.5,
speed = 0,
criticalChance = 0.05,
DOTTimer = 0.75, --it will be able to hurt every 0.5 seconds
curDOTTime = 0.75,
DOTApplied = false
},
[GameMaster]
GameMaster: init () can be seen from
Create characters in a unified manner and release them in batches
self: AddHeros ()
self: addMonsters ()
logicUpdate frame loop
Mainly responsible for controlling the progress of the hero and the refresh of the mobs
local battleSiteX = {-2800, -1800, -800}
Set the trigger location and refresh location
stage is 1 ~ 7
Randomly spawn or run to the right
stage == 7 clear the mobs
stage == 8 give warning
After the warning, the boss is displayed showBoss ()
It is not very configurable, so the code will not be analyzed here.
[ParticleManager] The plist contains two parts: particle system properties and particle texture
1. Load and create Quad particle objects with particle attributes. At startup, call AddPlistData to load the plist file of particles, and the cache is in map format.
From the interface implementation point of view, if the particles are created directly from the cached map, it saves the time of reading the file and plays an optimization role.
ParticleSystemQuad * ParticleSystemQuad :: create (ValueMap & dictionary)
{
ParticleSystemQuad * ret = new (std :: nothrow) ParticleSystemQuad ();
if (ret && ret-> initWithDictionary (dictionary))
{
ret-> autorelease ();
return ret;
}
CC_SAFE_DELETE (ret);
return ret;
}
2. Particle texture provided by FX.plist and FX.png
Texture the generated quad
magic: setTextureWithRect (magicf: getTexture (), magicf: getRect ())
3. Error about the console During debugging, the console has been reporting bugs, so I went to see the source code now and then, by the way, see how the overload of the lua function ParticleSystemQuad: create is implemented
error:
cc.ParticleSystemQuad: create argument # 2 is 'table'; 'string' expected.
int lua_cocos2dx_ParticleSystemQuad_create (lua_State * tolua_S)
{
int argc = 0;
bool ok = true;
#if COCOS2D_DEBUG> = 1
tolua_Error tolua_err;
#endif
#if COCOS2D_DEBUG> = 1
if (! tolua_isusertable (tolua_S, 1, "cc.ParticleSystemQuad", 0, & tolua_err)) goto tolua_lerror;
#endif
argc = lua_gettop (tolua_S) -1;
do
{
if (argc == 1)
{
std :: string arg0;
ok & = luaval_to_std_string (tolua_S, 2, & arg0, "cc.ParticleSystemQuad: create");
if (! ok) {break;}
cocos2d :: ParticleSystemQuad * ret = cocos2d :: ParticleSystemQuad :: create (arg0);
object_to_luaval <cocos2d :: ParticleSystemQuad> (tolua_S, "cc.ParticleSystemQuad", (cocos2d :: ParticleSystemQuad *) ret);
return 1;
}
} while (0);
ok = true;
do
{
if (argc == 0)
{
cocos2d :: ParticleSystemQuad * ret = cocos2d :: ParticleSystemQuad :: create ();
object_to_luaval <cocos2d :: ParticleSystemQuad> (tolua_S, "cc.ParticleSystemQuad", (cocos2d :: ParticleSystemQuad *) ret);
return 1;
}
} while (0);
ok = true;
do
{
if (argc == 1)
{
cocos2d :: ValueMap arg0;
ok & = luaval_to_ccvaluemap (tolua_S, 2, & arg0, "cc.ParticleSystemQuad: create");
if (! ok) {break;}
cocos2d :: ParticleSystemQuad * ret = cocos2d :: ParticleSystemQuad :: create (arg0);
object_to_luaval <cocos2d :: ParticleSystemQuad> (tolua_S, "cc.ParticleSystemQuad", (cocos2d :: ParticleSystemQuad *) ret);
return 1;
}
} while (0);
ok = true;
After reading the source code overloading, the idea is relatively clear: first determine the number of parameters, and then try to take the parameters in the L stack through the function luaval_to_std_string, respectively, until a certain type is correctly obtained
ok & = luaval_to_std_string (tolua_S, 2, & arg0, "cc.ParticleSystemQuad: create");
The error log is reported by the function luaval_to_native_err during the trial process
if (! tolua_iscppstring (L, lo, 0, & tolua_err))
{
#if COCOS2D_DEBUG> = 1
luaval_to_native_err (L, "# ferror:", & tolua_err, funcName);
#endif
ok = false;
}
Think about it a little bit. In fact, this code can be optimized. You can try all the branches you want to try first, and report errors if they are not correct.
[manager]
Maintain all the role objects, mainly responsible for handling collision events
collisionDetect frame loop
collision (sprite)-> solveCollision
Make sure the distance between the two characters is less than the "waistline" _radius of the two, and calculate the distance of the bounce based on the "weight" _mass of the two
isOutOfBound (sprite) ensures that the character will not come out of the screen
G =
{
winSize = cc.Director: getInstance (): getWinSize (),
bloodPercentDropSpeed = 2,
activearea = {left = -2800, right = 1000, bottom = 100, top = 700},
}
getFocusPointOfHeros Get the hero's "average position" as the camera focus
reference:
"particle"