DigoFreitas

  • Jun 10, 2020
  • Joined May 12, 2020
  • 0 best answers
  • @bitshift-r said: What happens when the player pushes the box? Are you applying an impulse to the box or setting its position?

    I had a moveable object once that was sinking into the floor, but it was a KinematicBody2D. Of course I had to integrate my own pushing, but I was also able to add pulling. Anyway, what was happening was that I was using move_and_slide to push the object down each frame to apply gravity, and counting on the collision detection to keep it on the floor. But when my player stood on top of it the collision couldn't resolve, so it would slowly sink.

    I ended up solving that problem by using move_and_collide with test_only set to true. Then I would only apply gravity only if I wasn't colliding with the ground.

    Cool tips about the test_only and the collision shape with angled corners. I'll try both!

    Currently I'm using RigidBody2D with Character mode, but it's not great yet...

    Here some gameplay I recorded. Box issues on the last minutes.

  • @bitshift-r said: I would try setting your box's continuous_cd to Cast Shape. That might help with the accuracy of the one way collisions.

    @bitshift-r said: Another thought... you could try increasing the one way collision margin on your platform's collider shape.

    Sadly neither of them worked. Only when I use full collision.

    When I try to change the RigidBody2D to Character mode, the box sometimes gets stucked while pushing.

  • I have a pushable box as a RigidBody2d (Rigid mode).

    As shown on this video, where left half of the tiles of this floor have full collision and half right have one way collision on top, the body slides through the right tiles.

    What could it be?!

    I tried to use Character and Kinematic Mode and they gave me another weird problems...

  • @TwistedTwigleg said: Hmm, it seems there is no option to lock rotation of a RigidBody2D like there is for RigidBody3D nodes. You might be able to work around this though by adding something like the following to your RigidBody node:

    func _physics_process(_delta):
    	angular_velocity = Vector2.ZERO

    I have not tried it myself, but I think that would cancel out any rotational velocity the box could have, which should make it no longer rotate.

    I searched about that yesterday before posting and I found this nice tutorial and demo: http://kidscancode.org/godot_recipes/physics/kinematic_to_rigidbody/

    But sadly your hint didn't work with "angular_velocity"... But I kept looking on this node properties and saw the "rotation degrees". Thought: "why not?" And worked!

    Here's the solution. Player as KinematicBody2d, using the demo from the link above. Added a script to the RigidBody2d (Ball.tscn) and did:

    extends RigidBody2D
    
    func _physics_process(delta):
    	self.rotation_degrees = 0

    To avoid boxes to going up I added the code below that removes "negative gravity", but it didn't avoid some bouncing, because the CollisionShape2d still rotating some way... But at least it isn't show the sprite "angled".

    if linear_velocity.y < 0: linear_velocity.y = 0

    Some tips to get it even better?

  • @cybereality said: Is that code for the player or the boxes? I'm a little confused. I think only the player should be a kinematic body. The boxes should be rigid bodies, I think the physics engine should handle that (though I haven't tried yet).

    Sorry, forgot to explain my approach. I'm using Kinematic for both player and box and this is the box script.

    Player is basically the one from Kinematic 2d platformer demo. I'd love to use RigidBody2d but I don't want it to spin, my boxes need to stay sligned with ground, always. If there is a solution using RigidBody2d that don't spin when touched, it would be awesome!

  • I'm building a simple "push the boxes" system, but something in my code isn't working as expected.

    When include at least one box over another and try to push them all, sometimes it just don't move until I move that top box a little bit.

    I tried to use RigidBody2d boxes, but it spins when touched... I need the boxes to be aligned to the ground. So this is all Kinematic2dBody.

    Any help will be very appreciated!

    ---

    The Player is basically the one from the Kinematic 2d platformer demo. Here's my GDS for the box:

    extends KinematicBody2D
    
    const PLAYER_SCALE = 2
    const FLOOR_NORMAL = Vector2(0, -2)
    const SLOPE_SLIDE_STOP = 25.0
    const WALK_SPEED = 150 # pixels/sec
    
    const TOP = 0
    const BOTTOM = 1
    const LEFT = 2
    const RIGHT = 3
    
    var linear_vel = Vector2()
    var direction = 0
    var on_floor = false
    var can_play_sound = true
    
    var top_area_bodies = []
    var bottom_area_bodies = []
    var left_area_bodies = []
    var right_area_bodies = []
    
    onready var box_sm = $box_sm
    onready var anim = $anim
    onready var player = global.get_player()
    
    func _ready():
    	reset()
    
    func reset():
    	global.boxes.append(self)
    
    func _apply_gravity(delta):
    	linear_vel.y += delta * global.GRAVITY
    
    func _apply_movement(delta):
    	var previous_direction = direction
    	var desaccel = 0
    	
    	direction = 0
    	
    	for surface in [TOP, BOTTOM, LEFT, RIGHT]:
    		check_surface(surface)
    	
    	if player.player_sm.is_on(player.player_sm.states.push): 
    		if player.siding_left:
    			for body in right_area_bodies:
    				if global.is_player(body) and box_sm.is_on(box_sm.states.idle):
    					if box_sm.is_on(box_sm.states.idle):
    						direction = -1
    					else:
    						direction = -1.5
    		elif !player.siding_left:
    			for body in left_area_bodies:
    				if global.is_player(body):
    					if box_sm.is_on(box_sm.states.idle):
    						direction = 1
    					else:
    						direction = 1.5
    	
    	if player.player_sm.is_on(player.player_sm.states.push) and direction == 0 and previous_direction != 0:
    		direction = previous_direction
    		if box_sm.is_on(box_sm.states.floating):
    			play_sound(global.sound_splash)
    		else:
    			play_sound(global.sound_push)
    	
    	if linear_vel.x != 0:
    		if linear_vel.x < 0:
    			for body in left_area_bodies:
    				if global.is_box(body):
    					body.linear_vel.x = linear_vel.x
    		elif linear_vel.x > 0:
    			for body in right_area_bodies:
    				if global.is_box(body):
    					body.linear_vel.x = linear_vel.x
    		
    		for body in top_area_bodies:
    			if linear_vel.x > 0 and linear_vel.x < body.linear_vel.x: return
    			elif linear_vel.x < 0 and linear_vel.x > body.linear_vel.x: return
    			body.linear_vel.x = linear_vel.x
    	
    	if box_sm.is_on(box_sm.states.idle):
    		desaccel = 0.5
    	else:
    		desaccel = 0.05
    	
    	linear_vel = move_and_slide(linear_vel, FLOOR_NORMAL, SLOPE_SLIDE_STOP)
    	linear_vel.x = lerp(linear_vel.x, direction * WALK_SPEED, desaccel)
    	on_floor = is_on_floor()
    	
    func check_surface(area):
    	var in_sewer = false
    	var body = null
    	
    	match area:
    		LEFT:
    			left_area_bodies.clear()
    			for body in $Area2D_left.get_overlapping_bodies():
    				if body == self: continue
    				if global.is_box(body) or global.is_player(body):
    					left_area_bodies.append(body)
    		RIGHT:
    			right_area_bodies.clear()
    			for body in $Area2D_right.get_overlapping_bodies():
    				if body == self: continue
    				if global.is_box(body) or global.is_player(body):
    					right_area_bodies.append(body)
    		TOP:
    			top_area_bodies.clear()
    			for body in $Area2D_top.get_overlapping_bodies():
    				if body == self: continue
    				if global.is_box(body):
    					top_area_bodies.append(body)
    		BOTTOM:
    			bottom_area_bodies.clear()
    			for body in $Area2D_bottom.get_overlapping_bodies():
    				if body == self: continue
    				if global.is_player(body):
    					linear_vel.y = -WALK_SPEED
    				if global.is_sewer(body):
    					in_sewer = true
    				if global.is_box(body):
    					bottom_area_bodies.append(body)
    			
    			if box_sm.is_on(box_sm.states.idle):
    				if in_sewer:
    					box_sm.set_state(box_sm.states.floating)
    			elif box_sm.is_on(box_sm.states.floating):
    				if !in_sewer:
    					box_sm.set_state(box_sm.states.idle)
    
    func play_sound(stream, force=false):
    	if not force and not can_play_sound: return
    	
    	can_play_sound = false
    	$sound.stream = stream
    	$sound.play()
    
    func _on_Area2D_top_body_entered(body):
    	if global.is_box(body):
    		global.set_all_zindex()
    
    func _on_sound_finished():
    	can_play_sound = true