Search code examples
javascriptandroidchipmunkcocos2d-js

Cocos2D-JS Chipmunk PhysicsSprite Move action not working in Android phone


I am trying to develop a simple cross-platform game, and trying to move a PhysicsSprite with a Body to the position I touched/clicked, using Cocos2D-JS.

Here is the code that I have:

var TAG_SPRITE = 1;

var AnimationLayer = cc.Layer.extend({
    space:null,

    ctor:function (space) {
        this._super();
        this.space = space;
        this.init();
    },
    init:function () {
        this._super();

        var winsize = cc.director.getWinSize();

        //init physics sprite
        var spriteHead = new cc.PhysicsSprite(res.Head_png);
        var headContentSize = spriteHead.getContentSize();

        //init body
        var headBody = new cp.Body(1, cp.momentForBox(1, headContentSize.width, headContentSize.height));
        headBody.p = cc.p(winsize.width / 2, winsize.height / 3);
        this.space.addBody(headBody);

        //init shape
        var headShape = new cp.CircleShape(headBody, headContentSize.width / 2, cp.v(0, 0));
        headShape.setFriction(0.3);
        headShape.setElasticity(0.8);
        this.space.addShape(headShape);

        spriteHead.setBody(headBody);

        this.addChild(spriteHead, 0, TAG_SPRITE);

        //for mobile
        if('touches' in cc.sys.capabilities ){
            cc.eventManager.addListener({
                event: cc.EventListener.TOUCH_ONE_BY_ONE,
                swallowTouches: true,
                onTouchBegan:function (touch, event) {
                    cc.log('touch began');
                    event.getCurrentTarget().moveSprite(touch.getLocation());
                    return true;
                },
                onTouchMoved: function (touch, event) {
                },
                onTouchEnded: function (touch, event) {
                },
                onTouchCancelled: function (touch, event) {
                }
            }, this);
        }
        //for desktop
        else if ('mouse' in cc.sys.capabilities ) {
            cc.eventManager.addListener({
                event: cc.EventListener.MOUSE,
                onMouseUp: function (event) {
                    event.getCurrentTarget().moveSprite(event.getLocation());
                }
            }, this);
        }
    },
    moveSprite:function(position) {
        cc.log('move to: ' + position.x + ',' + position.y);
        var sprite = this.getChildByTag(TAG_SPRITE);
        var moveAction = new cc.moveTo(1, position);
        sprite.runAction(moveAction);
    }
});

As I see the logs from the logcat, it can handle touch events but cannot move the sprite. When I convert the PhysicsSprite to just Sprite object and remove all other Body and Shape stuff, it can be moved to the location that I touch. The problem is that I can move the PhysicsSprite in the browser whereas I cannot do that in my Android phone.

Note: I use Chipmunk physics engine


Solution

  • I don't know this is the real solution or should be considered as a workaround but the code below works fine for both web and Android. But still don't know why the code in the question doesn't work for Android while it does for the web. (It would make more sense if it didn't work for both...)

    I tried to move body of the sprite instead of itself. The new moveSprite method is like that:

    moveSprite: function(sprite){
        cc.log('move to: ' + position.x + ',' + position.y);
        var sprite = this.getChildByTag(TAG_SPRITE);
        var body = sprite.getBody();
        var velocity = 300;
        this.moveWithVelocity(body, position, velocitiy);
    }
    

    moveWithVelocity is the custom function that I created in the same Layer, moving the Body to the destination point with a particular velocity:

    moveWithVelocity: function(body, destination, velocity){
        var deltaX = destination.x - body.p.x;
        var deltaY = destination.y - body.p.y;
        var distance = Math.sqrt(Math.pow(deltaX,2) + Math.pow(deltaY,2));
        var time = distance / velocity;
        var velocityX = deltaX / time;
        var velocityY = deltaY / time;
    
        //start the action with the calculated velocity in the calculated direction
        body.applyImpulse(cc.v(velocityX, velocityY), cc.v(0,0));
    
        //stop the sprite (or body here) when duration of movement is time out (or when the sprite/body arrives its destination)
        setTimeout(function(){
            body.setVel(cc.v(0,0));
        }, time*1000);
    
    }
    

    Hope this helps anyone encountered the same problem.