Collision detection not very good?

So - after a lot of hair pulling and gnashing of teeth - i've come to the conclusion that the physics implementation in Corona is not very strong...

I am trying to get a character / sprite to move (I don't want to make this reference, but it's the best way to describe it) like a doodle-jump character. Collision between the character and platform works probably 70% of the time. I've tried manipulating the "setPosition" and "SetVelocity" iteration methods and it doesn't seem to improve accuracy. Basically the sprite will occasionally vanish (with the x/y coords being reported as NaN), or it will pass through the top of the object. The object is not moving that fast...

Do I seriously have to roll my own collision system to get this to work??

This is a somewhat hacked together example of the problem. The cube can be moved by selecting the character and dragging down. Please note - this isn't very robust yet.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
-- Setup the game
-- Turn off the status bar
display.setStatusBar(display.HiddenStatusBar);
 
-- Setup graphics
local physics = require("physics");
physics.start();
physics.setDrawMode("hybrid");
physics.setGravity(0, 9.8);
physics.setPositionIterations(16);
physics.setVelocityIterations(6);
 
-- Setup the background group
local gameGroup = display.newGroup();
gameGroup.x = 0;
 
-- Ground object
local ground = display.newRect(450, 0, 320, 5);
ground.x = 160;
ground.y = 440;
ground.objectType = "ground"
groundPhysics = { -160, 0, 160, 0, 160, 10, -160, 10 };
physics.addBody(ground, "static", { density=1.0, friction=0.0, bounce=0.0, shape=groundPhysics });
gameGroup:insert(ground);
 
-- Setup a sprite for the player
playerInstance = display.newRect(100, 400, 32, 32);
playerInstance.x = 100;
playerInstance.y = 400;
playerInstance.rotation = 0;
gameGroup:insert(playerInstance);
physics.addBody(playerInstance, "dynamic", { density=0.25, friction=0.15, bounce=0.0 });
playerInstance.isFixedRotation = true;
playerInstance.objectType = "player";
 
-- Setup some vars on the playerInstance
playerInstance.isFalling = false;
playerInstance.xVel = 0;
playerInstance.yVel = 0;
 
-- Test jump platform
local jumpPlatform = display.newRect(80, 200, 100, 50);
jumpPlatform.objectType = "jumpPlatform"
gameGroup:insert(jumpPlatform);
physics.addBody(jumpPlatform, "static", { friction=0.3, isSensor=true} );
 
 
-- The main loop
function onEnterFrame(event) 
        
        -- Move the game world to keep the player onscreen
        if playerInstance.y <= 200 then
                gameGroup.y = -playerInstance.y + 200;
        end     
end
 
-- When the player makes a tap event
function onTouch(event)
 
        local t = event.target;
        local phase = event.phase;
 
        if phase == "began" then
                -- Make the object the topmost object
                local parent = t.parent;
                parent:insert(t);
                display:getCurrentStage():setFocus(t);
                
                -- Prevents spurious messages being sent
                t.isFocus = true;
                
                -- Store the initial position
                t.x0 = event.x - t.x;
                t.y0 = event.y - t.y;
                
        elseif t.isFocus == true then
        
                if phase == "moved" then
                
                elseif phase == "ended" or phase == "cancelled" then
                        
                        local xForce = (-1 * (event.x - playerInstance.x)) * 2.75;
                        local yForce = (-1 * (event.y - playerInstance.y)) * 2.75;
                
                        playerInstance:applyForce( 0, yForce, playerInstance.x, playerInstance.y);
                                        
                        display.getCurrentStage():setFocus(nil);
                        t.isFocus = false;
                        
                end
                
        end
        
end
 
local function onCollision(self, event)
 
        local other = event.other.objectType;
 
        xVel, yVel = playerInstance:getLinearVelocity();
        
        --debugTextField1.text = "collision between: " .. self.objectType .. " and " .. other;
                
        if event.phase == "began" then
                
                if (yVel > 0) then
                        event.other.isSensor = false;
                end
                
        elseif event.phase == "ended" then
                event.other.isSensor = true;
        end
        
end
 
-- Setup the event listeners
playerInstance.collision = onCollision;
playerInstance:addEventListener("collision", playerInstance);
Runtime:addEventListener("enterFrame", onEnterFrame);
playerInstance:addEventListener("touch", onTouch);

How often are you getting this result? I just tried about 40 times and couldn't replicate it unless I moused down and out of the simulator which obviously isn't an issue on device.

Were you getting it 70% with this code, or in your actual project?

This code - on the simulator. Very frequently. Just got it first time I tried, with that exact code. I just selected the square, dragged down (within the simulator window) and released. The square went just above the platform, landed on the platform - and vanished. I'm assuming it didn't actually vanish, but was ejected very quickly (linear velocity goes through the roof when this happens).

Just tried this on the device - and I get the same behavior.

try to set fps to 60, for a similar problem it worked for me.

Thanks for the suggestion - it appears to improve matters. But definitely doesn't solve it. I still get the "player" disappearing occasionally. There is something truly whacky going on.

views:1319 update:2011/11/3 16:17:22
corona forums © 2003-2011