CCPhysicsjoint not keeping the 2 bodies intact - cocos2d-x

I want to add a particle body(say Fire) before another physics body(the arrow).
So, i am using the spring joint to keep them joined with stiffness around 20000, but still its starting the correct way and the particle-body swings away form the arrow. Here's my code:
fire part
CCParticleSystem *explosion= [CCParticleSystem particleWithFile:#"bomb.plist"];
explosion.position = ccpAdd(projectilePos, ccp(16,0));
explosion.physicsBody.mass=1.0;
explosion.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:16.0 andCenter:explosion.anchorPointInPoints];
explosion.physicsBody.type=CCPhysicsBodyTypeDynamic;
explosion.physicsBody.affectedByGravity=FALSE;
explosion.physicsBody.allowsRotation=FALSE; //so that fire flames go upwards only, and not rotate
[physicsWorld addChild:explosion];
explosion.physicsBody.collisionMask=#[];
arrow part
CCSprite *tempSprite;
tempSprite = [CCSprite spriteWithImageNamed:#"arrow3#2x.png"];
[tempSprite setScale:0.05];
[tempSprite setScaleY:0.15];
tempSprite.rotation=rotation;
tempSprite.position=dummyBow.position;
tempSprite.name=[NSString stringWithFormat:#"%#,%d",[lifeOfSprite[1] objectForKey:#"name"],[[lifeOfSprite[1] objectForKey:#"life"] intValue]];
tempSprite.physicsBody = [CCPhysicsBody bodyWithRect:(CGRect){CGPointZero, tempSprite.contentSize} cornerRadius:0]; // 1
tempSprite.physicsBody.collisionGroup = #"playerGroup";
tempSprite.physicsBody.collisionType = #"projectileCollision";
[physicsWorld addChild:tempSprite z:0];
projectile.physicsBody.mass=100;
now the joint part
[CCPhysicsJoint connectedSpringJointWithBodyA:playerBomb.physicsBody bodyB:projectile.physicsBody anchorA:ccp(1,1) anchorB:ccp(600,0) restLength:0.f stiffness:20000.f damping:60.f];
(debugDraw)
the fire should come at the front, but swings back from front by spring effect
Can anyone tell where's the problem?
Thanks in advance.

Related

How to wait, then do something, in the GameScene

SKAction has waiting for duration abilities, for a period of time on a node. And seems to perform actions on nodes. Like moveTo, etc.
If I don't want that, rather I'd prefer to call functions within GameScene after a period of time, how do I do that with SpriteKit in the GameScene, not on a Sprite or other Node?
Are SKActions the way to do this? The only way to do this?
Yes. This question IS that ridiculously simple. I lack the heuristics and terminology to find an answer. Just keep looping around on how SKAction waits are calls on SKSprites for things like scale, rotation, etc, after time. Which isn't want I want/need.
Update:
Desired outcome, inside GameScene
doSetupStuff() // does some stuff...
waitForAWhile() // somehow wait, perhaps do somethings in here, while waiting
doSomethingElse() // does this after the waitForAWhile has waited
UPDATE 2:
What I think happens, again, inside didMove(to view...)
func wait(){
let timeToPause = SKAction.wait(forDuration: 3)
run(timeToPause)
}
let wontwait = SKAction.wait(forDuration: 3)
run(wontwait)
thisFunction(willnot: WAIT"it starts immediately")
wait()
thisFunction(forcedToWait: "for wait()'s nested action to complete")
UPDATE 3:
Found a way to get the delay without using SKActions. It's a little crude and brutal, but makes more sense to me than SKActions, so far:
DispatchQueue.main.asyncAfter(deadline: .now() + 10.0) {
print("I waited ten seconds before printing this!")
}
An option, as you cited, is to manage this externally. The way I typically manage this sort of thing is to have an externally run update cycle. One that
To drive this updater, you could use either CADisplayLink (which is what I use right now with my OpenGL renderer) or a dispatch source timer (which I have used with my SpriteKit engine). When you use an updated, you want to calculate the delta time. The tick handler could look something like:
func tickHandler() {
let currTime = NSDate().timeIntervalSince1970
let dt = lastTime - currTime // lastTime is a data member of the class
// Call all updaters here, pretend "updater" is a known updater class
updater.update(dt)
}
And updater's update method would look something like:
func update(deltaTime:NSTimeInterval) {
// Do your magic
}
I typically have a main overall updater running independent of what people are calling scenes. Example usage would be something like having an attract mode like in old school arcade games. There they show title screen, sample game play, high scores, rinse and repeat. Scenes would be title, game play, high score. Here you can your main updater manage the time and coordinate the construction/destruction/switching of the scenes. Note this implies having an overall scene manager (which is actually quite handy to have).
For your case, you could use this updater to drive the GameScene updater. It's updater could look something like:
func update(deltaTime:NSTimeInterval) {
switch state {
case .SetupState:
// noop?
println("I'm in setup") // Shown just so you can see there is a setup state
case .WaitState:
waitTime += deltaTime
if waitTime >= kWaitTime {
// Do whats you gots to do
doSomethingElse()
state = .NextState
}
case .NextState:
// blah blah blah blah
}
}
So the flow to do this call path from your driver (CADisplayLink or dispatch source) would be something like:
tickHandler -> master updater -> game scene updater
Some will def find this is perhaps a little heavy handed. I, on the other hand, find this very helpful. While there is obviously some time management and the loss of being able to fire and forget, it can help provide more control for orchestrating pieces, as well as arbitrarily changing state without having to worry about killing already queued actions. There is also nothing that says you still cannot mix SKAction. When I did use SpriteKit, I did all my updating this way along with some dispatched items. I only used SKAction to update hierarchy. Keep in mind that I used my own animation and physics system. So at least for me I had a lot less dependency on SpriteKit (it effectively was just a renderer for me).
Note you have to have your own means to handle pause and coming to foreground where your timer will need to be resynced (you only need to worry about tickHandler). Breakpoints also will cause time jumps.
You can use below function
#define ANIM_TIME 2
SKAction *customACtion = [SKAction customActionWithDuration: ANIM_TIME actionBlock:^(SKNode *node, CGFloat elapsedTime) {
// Do Something Here
}];
Another way to make something happen after a certain period of time is to make use of the 'current time' parm passed to update(). The following code will spawn a boss at intervals ranging from 20 to 30 seconds.
In your property definitions:
var timeOfLastBoss: CFTimeInterval = -1 //Indicate no boss yet
var timePerBoss = CFTimeInterval()
.
.
.
didMoveToView() {
...
timePerBoss = CFTimeInterval(Int.random(20...30))
'''
}
.
.
.
func update(currentTime: CFTimeInterval) {
...
spawnBossForUpdate(currentTime)
...
}
'
'
'
func spawnBossForUpdate(currentTime : CFTimeInterval) {
if ( timeOfLastBoss == -1 ) {timeOfLastBoss = currentTime}
if (currentTime - timeOfLastBoss < timePerBoss) {return}
// Rest of 'spawnBoss code
self.timePerBoss = CFTimeInterval(Int.random(20...30))
self.timeOfLastBoss = currentTime
}
One way, using SKActions, in Swift 3.0, looks like this:
DEFINE: aPatientlyWaitingFunction() at the top level of
GameScene class.
To cause a delay to happen before calling the above function, inside
didMove(to view...)
three ways I've found to do this using Actions:
All three ways seem to accomplish the exact same thing:
let timeToWait: TimeInterval = 3 // is seconds in SKAction thinking time
let waitSomeTime = SKAction.wait(forDuration: timeToWait)
// 1st way __________________________________________
// with a completion handler, the function can be called after Action
run(waitSomeTime) {self.aPatientlyWaitingFunction()}
// 2nd way __________________________________________
// as a completion to be done after action, in the run invocation:
run(waitSomeTime, completion: aPatientlyWaitingFunction)
// 3rd way __________________________________________
// alternatively, as part of a sequence of actions...
// Create a sequence, by making a run action from waitSomeTime and...
let thenDoThis = SKAction.run(aPatientlyWaitingFunction)
// then activate sequence, which does one action, then the next
run(SKAction.sequence([waitSomeTime, thenDoThis]))
// OR... for something different ____________________
////////////////////////////////////////////////////////
DispatchQueue.main.asyncAfter(deadline: .now() + timeToWait) {
self.aPatientlyWaitingFunction()
print("DispatchQueue waited for 3 seconds")
}

how to connect a number variable to dynamic text in actionscript 3.0?

i know this might be simple but i have been searching everywhere for a fix but i just cannot find it!
i want to make something like a health #, so when you press whatever button the dynamic text # will go up or down. on my test project i have two layers, the first with the following code
var hp:Number = 100;
health.text = String hp;
hp being the variable, and health being the dynamic text. then i have the next layer with the button with:
function button(e:MouseEvent):void
{
hp -= 10;
}
without that second chunk of code, the dynamic text will appear, but once that is added it will disappear and the button is function-less.
how do i make this work??? once again sorry if this is a dumb question, i'm just very stumped.
The accepted answer is good, but I wanted to point out that your original code was actually very close to being correct, you just needed parenthesis:
health.text = String(hp);
For most objects String(object) and object.toString() has the same effect, except that object.toString() throws an error if object is null (which could be desirable or undesirable, depending on what you expect it to do).
This is not correct:
health.text = String hp;
use:
health.text = hp.toString();
and:
function button(e:MouseEvent):void
{
hp -= 10;
health.text = hp.toString();
}

Character hitTest Wall

The problem with my current platform game project is that the character stops before hitting a wall on the character's left side, and stops too late on the right side of the character.
Here is the script related to the problem:
char.topBumping=false;
char.bottomBumping=false;
char.leftBumping=false;
char.rightBumping=false;
char.speed=0;
char.maxSpeedConstant=10;
char.minSpeedConstant=-10;
char.xVel=0;
char.yVel=0;
stage.addEventListener(Event.ENTER_FRAME,EnterFrame);
function EnterFrame(e:Event){
//local points
top_left_point_local = new Point(char.top_left.x,char.top_left.y);
bottom_left_point_local = new Point(char.bottom_left.x,char.bottom_left.y);
top_right_point_local = new Point(char.top_right.x,char.top_right.y);
bottom_right_point_local = new Point(char.bottom_right.x,char.bottom_right.y);
//global points
top_left_point = new Point(char.localToGlobal(top_left_point_local).x,char.localToGlobal(top_left_point_local).y);
bottom_left_point = new Point(char.localToGlobal(bottom_left_point_local).x,char.localToGlobal(bottom_left_point_local).y);
top_right_point = new Point(char.localToGlobal(top_right_point_local).x,char.localToGlobal(top_right_point_local).y);
bottom_right_point = new Point(char.localToGlobal(bottom_right_point_local).x,char.localToGlobal(bottom_right_point_local).y);
if(ground.hitTestPoint(top_left_point.x,top_left_point.y,true)){
char.leftBumping=true;
}
if(ground.hitTestPoint(bottom_left_point.x,bottom_left_point.y,true)){
char.leftBumping=true;
}
if(!ground.hitTestPoint(top_left_point.x,top_left_point.y,true)&&!ground.hitTestPoint(bottom_left_point.x,bottom_left_point.y,true)){
char.leftBumping=false;
}
if(ground.hitTestPoint(top_right_point.x,top_right_point.y,true)){
char.rightBumping=true;
}
if(ground.hitTestPoint(bottom_right_point.x,bottom_right_point.y,true)){
char.rightBumping=true;
}
if(!ground.hitTestPoint(top_right_point.x,top_right_point.y,true)&&!ground.hitTestPoint(bottom_right_point.x,bottom_right_point.y,true)){
char.rightBumping=false;
}
if(char.rightBumping){
if(char.xVel>0){
char.xVel=0;
char.speed=0;
}
}
if(char.leftBumping){
if(char.xVel<0){
char.xVel=0;
char.speed=0;
}
}
char.x+=char.xVel;
char.y+=char.yVel;
}
Has anyone else encountered this problem? Any help will be much appreciated.
Update:
This is the heart of the problem, for some reason the character hitting the left wall comes out true here even while the character is standing still (left is not being pressed).
Well, after many aggravating hours I finally solved the problem. The orientation of the inside of a movieclip determines its overall position. I never knew that. I always thought it didn't matter how the inside of a movieclip was positioned in relation to the movieclip's center. Lesson learned, always center the inside of movieclips to the mc's stage to simplify things.

AS3 unwanted delay between playing audio

I have a song chopped up into 4 pieces: intro, A, B, ending. I have a program that plays the intro, then the A two times then B two times then back to A again and keeps repeating AABB until I press the ending button. If the ending button is pressed, it finishes the currently playing song piece, plays the ending and stops. It works like a charm except there is a very noticeable, irritating delay in the transition between the song pieces. How can I get rid of the delay and make it play the song pieces right after the previous piece ends? (I'm using actionscript 3.0 in flash cs6, the song pieces are in mp3 format, imported into the library).
Here's the program:
https://dl.dropboxusercontent.com/s/6f9w906x9uja683/Loop%20music%20test.swf
And here's the code I'm using:
import flash.events.MouseEvent;
stop();
//variables
var track_var: Number = 0;
var music_cnl:SoundChannel = new SoundChannel();
var intro_msc:Sound = new intro_mp3();
var a_msc:Sound = new A_mp3();
var b_msc:Sound = new B_mp3();
var outro_msc:Sound = new ending_mp3();
//stopping the movieclips
a_mc.stop();
b_mc.stop();
ending_btn.stop();
//intro
music_cnl = intro_msc.play();
track_var= 1;
intro_mc.gotoAndStop(2);
music_cnl.addEventListener(Event.SOUND_COMPLETE, playnext_fn);
trace("debug:track value set to",track_var);
//track selector
function playnext_fn(event:Event){
trace("debug:playnext_fn called");
switch(track_var){
case 0:
//stop
music_cnl.stop();
intro_mc.gotoAndStop(1);
a_mc.gotoAndStop(1);
b_mc.gotoAndStop(1);
ending_btn.gotoAndStop(1);
trace("debug:track value set to",track_var);
ending_btn.removeEventListener(MouseEvent.MOUSE_UP, ending_fn);
break;
case 1:
//first A track
track_var=2;
intro_mc.gotoAndStop(1);
b_mc.gotoAndStop(1);
a_mc.gotoAndStop(2);
music_cnl= a_msc.play();
music_cnl.addEventListener(Event.SOUND_COMPLETE, playnext_fn)
trace("debug:track value set to",track_var);
break;
case 2:
//second A track
track_var=3;
music_cnl= a_msc.play();
music_cnl.addEventListener(Event.SOUND_COMPLETE, playnext_fn);
trace("debug:track value set to",track_var);
break;
case 3:
//first B track
track_var = 4
a_mc.gotoAndStop(1);
b_mc.gotoAndStop(2);
music_cnl= b_msc.play();
music_cnl.addEventListener(Event.SOUND_COMPLETE, playnext_fn);
trace("debug:track value set to",track_var);
break;
case 4:
//second B track
track_var=1;
music_cnl= b_msc.play();
music_cnl.addEventListener(Event.SOUND_COMPLETE, playnext_fn);
trace("debug:track value set to",track_var);
break;
case 5:
//ending
a_mc.gotoAndStop(1);
b_mc.gotoAndStop(1);
intro_mc.gotoAndStop(1);
ending_btn.gotoAndStop(2);
music_cnl=outro_msc.play();
track_var=0;
music_cnl.addEventListener(Event.SOUND_COMPLETE, playnext_fn);
trace("debug:track value set to",track_var);
break;
}
}
//ending button
ending_btn.addEventListener(MouseEvent.MOUSE_UP, ending_fn);
function ending_fn(Event:MouseEvent){
track_var=5;
ending_btn.gotoAndStop(2)
trace("debug: ending button pressed|","track value set to",track_var);
}
I don't see a problem with your code (other than the redundant and incorrect syntax regarding
MAX_BUFFERSIZE, but I think this just looks like remnants of trying to resolve the problem!)
What I think is more likely to be causing the problem is your source audio - if it's imported as an MP3, or with a bitrate of 48 this can cause problems with synching.
You can't get rid of the delay using traditional Sound object whether from library, loaded externally, mp3, wav, any bite rate. The Flash Sound API suffers from a bad design and latency is inevitable when playing sounds.
However in your case you might be abe to get away with it by using the SampleEventData and mix together all your tracks. The initial latency can go up to 1000ms but in your case that might be irrelevant since the sync between sound is more important:
http://help.adobe.com/en_US/as3/dev/WSE523B839-C626-4983-B9C0-07CF1A087ED7.html
When playing Sounds in Flash in ANY WAY the latency (the time it takes for the sound to start playing) can go from 60ms to 400ms depending on the system. The recommended industry standard is 30ms making Flash an obsolete technology for any Sound related applications.

erasing a layer where mouse is over it

I got the following question.
i added the following elements to the stage:
homeBg = new HomeBg();
homeMask = new HomeDrawBg();
addChild(homeBg);
addChild(homeMask);
I allready instantiated them in the beginning of the document. But my problem is the following. the homeBg layer is a image, the homeMask layer is the same image but it has a pencil scetch look. What i want is that wherever i move my mouse, the homemask layer should be erased so the bottom layer becomes visible(only where the mask is erased). So how can i tell the mask layer to erase itself if the mouse is over it?
Answer attempt 2
You can use the blendMode property of a display object to achieve this. Here's the code (tested):
// set the eraser width (diameter)
var eraserWidth:int = 20;
//get the HomeMask library item
var homeMask:HomeMask = new HomeDrawBg();
homeMask.blendMode = BlendMode.LAYER;
addChild(homeMask);
// create the eraser shape
var eraser:Shape = new Shape();
eraser.graphics.beginFill(0x000000);
eraser.graphics.drawCircle(0,0,eraserWidth/2);
eraser.blendMode = BlendMode.ERASE;
homeMask.addChild(eraser);
homeMask.addEventListener(MouseEvent.MOUSE_MOVE,mouseOverMask);
function mouseOverMask(evt:MouseEvent):void
{
eraser.x = homeMask.mouseX;
eraser.y = homeMask.mouseY;
}
There are a couple of important bits here.
Firstly, you must set the blendMode of the thing you want to erase to BlendMode.LAYER.
Secondly (and this is what has tricked me before) your eraser, with BlendMode.ERASE, must be a child of the object you're wanting to erase.
Have a look on the following:http://www.piterwilson.com/personal/2008/05/07/bitmapdata-erasing-in-as3-with-custom-brush-shape/