Passing through an object which has physics

Hey, i’m still an amateur at making games. Right now i’m working at making a 2D Hack n Slash kind of game. My problem is i don’t how to make my hero to pass through an enemy. I use physics on both of the hero and the enemy, i already make the .isSensor false but it is still not passing through the enemy, and i already use .isBodyActive which make it possible but the enemy is not having a physics anymore. Can somebody help me? Thank you so much for the help.

If you do want the objects to be able to pass through each other, then you want to set isSensor to true. Sensors only detect collisions, but they don’t actually collide with other objects.

You’ll likely need to give your enemies multi-element bodies, see:

And more about multi-element collisions:

You’ll need to create at least 2 elements for the enemy’s physics body, each element with their own collision filter. One being the enemy’s “shape” that can collide with the player, but not with the level. The other being the enemy’s “feet”, or just the same “shape” as before, and this would collide with the level, but not the player. You can make the element that can collide with the player into a sensor, so the player can pass through the enemy. The “feet” shape then keeps the enemy a physical body that keeps them in the level.

You can read about collision filtering here:

Thanks bro, it really helps!
Also i want to ask something but not about physics. I have an “attack” sequence of a sprite where if the loopcount = 0, it will run all 4 frames, but when i turn it to loopcount = 1, the last frame is skipped. I already tried to delay the idle sequence before its done attacking but it doesn’t help. There are 4 types of enemy but only this sprite has this kind of problem.

If I understood correctly, 4 animated objects are setup the same way, but only one of them has the issue? Maybe the sprite sheet setup is off?
Would you be able to isolate the code in question to further troubleshoot?

Yes, i setup the sheet frame per frame.

local buto_sheet = graphics.newImageSheet( "assets/enemy/Buto_Ijo-Sheet.png", {
        frames = {
			--idle
			{
				x = 1, y = 60,
				width = 150,height = 105
			},
			{
				x = 208, y = 60, 
				width = 150,height = 105
			},
			{
				x = 414, y = 60,
				width = 150,height = 105
			},
			{
				x = 624, y = 60,
				width = 150,height = 105
			},
			--walk
			{
				x = 1, y = 220,
				width = 155, height = 110
			},
			{
				x = 198, y = 220,
				width = 155, height = 110
			},
			{
				x = 416, y = 220,
				width = 158, height = 110
			},
			{
				x = 618, y = 220,
				width = 150, height = 109
			},
			--attack
			{
				x = 30, y = 390,
				width = 104, height = 100
			},
			{
				x = 220, y = 375,
				width = 136, height = 115
			},
			{
				x = 410, y = 335,
				width = 166, height = 155
			},
			{
				x = 680, y = 335,
				width = 156, height = 155
			},
		}
    })

	local buto_sequenceData = {
		{ name = "idle", frames = { 1, 2, 3, 4 }, time = 700, loopCount= 0 },
		{ name = "walk", frames = { 5, 6, 7, 8 } , time = 800, loopCount = 0 },
		{ name = "attack", frames = {9, 10, 11, 12}, time = 700, loopCount = 1}	
	}	
                Enemy = display.newSprite( parent,buto_sheet, buto_sequenceData )
		Enemy.x, Enemy.y = x, y
		Enemy.anchorY = 1
		Enemy:setSequence( "idle" )
		Enemy:play()

just like what i said, the animation is good if the loopcount = 0, but once the loopcount = 1 the last frame is skipped. The animation which has problem is the “attack” sequence

I also just tested with what I could on my end and couldn’t replicate the issue

If you can replicate the issue on a separate project and posted here we can take a closer look.

I don’t know how to post a project in this forum. Instead i’m gonna give you the sprite that i used.

I copied and pasted your code, used your sprite sheet; everything is working fine for me.
Are you changing sequence after attack is completed? The attack sequence by itself plays all 4 frames.

Side note, the sprite sheet already has the frames aligned so that you don’t need to specify the frames, thus you can use this instead:

local options = {
	width = 836/4,     -- sheet width / total columns
	height = 492/3,    -- sheet height / total rows
	numFrames = 12     -- columns * rows
}
local buto_sheet = graphics.newImageSheet( "assets/enemy/Buto_Ijo-Sheet.png", options )

I didn’t now i can make options like that, thanks for that!
Well basically i change the sequence to idle after attacking. So, my simple enemy logic is when it’s near the hero, he will get “idle” sequence then after the attacking cd reach 0, he will attack after the attack I change it again to idle. The way I checked if the enemy is done attacking or not, I use this logic.

if value.sequence == "attack" then
            if not value.isPlaying then 
		        timer.performWithDelay( 200, value:setSequence("idle") )
                timer.performWithDelay(200, value:play())
            end
end

I put this logic in enterFrame(). It works with the other enemy, but this one always skipping the 4th frame.

OK, now that makes sense. The logic will trigger as soon as 4th frame kicks in and therefore will be changed before it’s even visually seen.

First, a fix for your timers:

timer.performWithDelay( 200, function() value:setSequence("idle") end )
timer.performWithDelay( 200, function() value:play() end )

or

timer.performWithDelay( 200, function() 
   value:setSequence("idle")
   value:play() 
end )

Reason being, function should be passed as a variable, and it will be called when the specified time has been completed. If you add () to your function (per original code) it’ll call the function right away. Since your functions have parameters then the above would be the way to do it.

I don’t know whether that will fix your issue or not, however, you can still go about it using a sprite event listener; in this case it’s whatever works best for you.

Because of the way the listener works, you would still need a timer as you have done, however, if you simply repeat the last frame in your sequence you’ll get the same effect but without the need to use timers:

local function spriteListener( event )
    local sprite = event.target  -- "event.target" references the sprite
 
    if ( event.phase == "ended" ) then 
		if sprite.sequence == "attack" then	-- this assumes it has a sequence with this name
			sprite:setSequence( "idle" )  -- set to new sequence
			sprite:play()  -- start playing the sequence
		end
    end
end

local buto_sequenceData = {
	{ name = "idle", frames = { 1, 2, 3, 4 }, time = 700, loopCount= 0 },
	{ name = "walk", frames = { 5, 6, 7, 8 } , time = 800, loopCount = 0 },
    -- notice repeated extra frame at the end; time may need to be adjusted
	{ name = "attack", frames = {9, 10, 11, 12, 12}, time = 700, loopCount = 1}
}
Enemy = display.newSprite( buto_sheet, buto_sequenceData )
Enemy.x, Enemy.y = 100,150
Enemy.anchorY = 1
Enemy:addEventListener("sprite", spriteListener)
Enemy:setSequence( "attack" )
Enemy:play()