When I start a matter.sprite movement in Phaser 3 with sprite.setVelocity(vx, vy), how can I easily check if the movement ended?
The problem is that sprite.body.velocity.x == 0 seems to be only true in the case when the sprite bounces off of an obstacle, and momentarily stops. But I need to know when the whole movement actually ended.
Well, this was a problem on my side. I was testing a maximum velocity of all objects to check if there is a movement on the scene. But I was doing it like this:
maxVelocity.x = Math.max(maxVelocity.x, child.body.velocity.x);
Which doesn't work well with negative values. Math.abs(...) was needed :)
Related
So when my player falls off the map, I want the level to reload. I have used an area2d with a collisionshape2d to create an area that will call a function when the player collides with this area. However, when the game is run with this code included, the player will animate through a few frames then the game completely freezes before I can even move the player.
func _on_Area2D_body_entered(body):
get_tree().reload_current_scene()
If I delete this code, or set monitoring to off, and re-run the game it will not freeze.
Below is a screenshot of my level design.
Level design
Any help would be greatly appreciated :) - Is this a bug or am I doing something stupid?
When I set a breakpoint on the get_tree().reload_current_scene() line the following report shows
debugger
does this mean the player is colliding with a tile - If this is the case I don't see how as the program freezes before the player touches the ground.
As I said in the comments, this line:
get_tree().reload_current_scene()
Returns a value.
Now, you have said that 0 is "continuously outputted". In this context 0 means OK, in other words: it was able to reload the scene. The problem is the "continuously" part. It means that the scene reloads and then this code is triggered, and then it reloads again, and then this code is triggered again, and so on.
Now, apparently the Area2D is colliding with the TileMap. That makes sense. If it is a collision between the Area2D and a tile upon loading the scene, you would get the observed behavior. And the way the Area2D and TileMap are positioned in the scene supports the idea.
And about fixing it. I'll give you three solutions, either of these will work, with their drawbacks and caveats:
Don't have the Area2D positioned in a way that intersects non-passable tiles. This is easy to do by moving the Area2D further down, or by removing any tiles that overlap it.
The drawback with this approach is that it is fragile. You may forget in the future and move the Area2D or add tiles or something else that make the problem return. Also, it might not work well with your intended scenario design.
Change the collision_mask and collision_layer in such way that the tiles and the Area2D do not collide. As long as the bits from the mask do not overlap the bits from the layer of the other and viceversa, Godot will not even check for a collision between them.
The main drawback with this approach is that you have limited number of layers.
There is also the fact that it is less intuitive that simply placing things in such a way they don't collide.
To make it easier to work with, assign layers to different kinds of thingsā¦ Go to your Project Settings, on the General Tab, under Layer Names, and 2D Physics, and give them names (e.g. "environment", "enemies", "enemy bullets", "player", "player bullets", "items", "others").
Then you can assign to each object on collision_layer what they are, and on collision_mask set every thing they MUST collide with. With the caveat that Godot will check both ways.
In this case you would set the collision_layer of the player character physics object (the KinematicBody2D) to "player" (or similar), and put the collision_mask of the Area2D to the same, so they collide. Have the collision_layer of the TileMap set to something else (e.g. "environment") that is not in the collision_mask of the Area2D, so the Area2D and the TileMap do not collide. And set the collision_mask of the player character to something that include the layer you set to the TileMap, so the player character also collides with it. I hope that makes sense.
And, of course, you can filter on the Area2D, with a little of code. It can be checking the class, or node group, or the name of the physics body. For example you can insert at the start of the method something like this: if body.name != "player": return. So that it exits the method before it reaches reload_current_scene unless it is the correct physics body.
The drawback with this approach is that it is still checking and registering the collision, so it has worse performance that using collision_mask and collision_layer. But it will work, and it will perform OK for a small to mid sized game.
For more complex situations, you may employ a combination of these approaches (because, as I said, there is a limited number of layers, so you need to add filtering on top of it). I have a more detailed explanation of how to setup physics objects, including the techniques mentioned here, in another answer.
Video of what's happening exactly
Specs are:
Display being recorded 2560x1080#60hz
Display that the window goes offscreen 3840x2160#24hz (tested with 60hz too)
Windows 10
GPU Nvidia 970 GTX
Just started learning godot this week and lost hours to this strange behavior.
Godot specifics:
Scale of shapes and bodies are not modified (not to mess with physics)
Starting out trying to create an Entity class, that extends KinematicBody2D, to create instances of enemies within my game. Just using the dummy block for now to test if collisions are indeed working (stopped here due to what happened on the video)
The big dummy square that has one square texture is said Entity, with a collision with huge Y size just to test things out.
The area2d I want to trigger the signal is the small rectangle in front of the character.
Is there something I should know that is causing the signal to only fire while the debug window is on the other display? Should I just move the debug window to the other display and trust the game will work?
Code snippets
Creation of Area2D inside my animation controller
func _create_shape_with_collision(s : Shape2D, parentNode : Node) -> Node:
var ret = Area2D.new()
ret.connect('body_entered', self, '_check_body_entered')
var c = CollisionShape2D.new()
c.shape = s
parentNode.add_child(ret)
c.disabled = true
c.name = 'collision_shape'
ret.add_child(c)
return ret
signal function
func _check_body_entered(body : Node):
print(body.name)
PS: Attempted to type some stuff to help with autocomplete within Godot's interface, but my created classes were not working properly.
PS2: posted this same message on godot's reddit page, in hopes of better visibility
Make sure you have a matching Collision layer and mask in the Area2D node.
Shape2D is a resource, meaning if you don't create .new() then all CollisionShape2D are using the same instance of the shape. If anyone sets explicitly it free it's gone for everyone (so try printing if you accidentally are assigning a null shape). There's some weirdness on resizing after assigning not happening when CollisionShape2D is ready.
But also you have c.disabled = true that probably shouldn't be there.
Because #Theraot laid a path towards writing an issue on Godot's Github page, I was able to determine the cause of the above bug, while creating a minimal project.
In fact, it does not relate at all with the code, but on project settings. The physics FPS was set at 60, while my secondary screen was able to capture the event, as VSYNC was also on by default (caps FPS at refresh rate, secondary screen is 24hz).
Increasing the physics FPS to 120 (empyrical at this point) made the signal work on all displays.
Will gladly accept a better answer, explaining what are the impacts of changing such number (the strain on devices etc), if it is a bad practice or if there is another way to configure individual faster ticks for Area2Ds or PhysicsBody2Ds. Could not write such answer due to my current lack of knowledge/research. Trying to write it at this point would be a sophism.
Since i'm just coding some basic game elements while writing a Game Design Document, it's so far so good for me.
Edit:
After an insight from user #Theraot, I overlooked how different _process and _physics_process worked; For my use case, most of what I was doing should be inside _physics_process, so I could revert the engine's physics FPS back to default value.
I have 4 (0-3 animation frames) different images of a coin animation with differet states of it spinning. I would like to make it look like its spinning by adding another 2 frames (4-5) to make it look like it spins. In current situation it looks like the coin spins 180 degrees and goes back to it's original position. I would like to flip vertically ONLY the 4th and 5th frame. How can i achieve that without making new redundant pngs?
I know making 2 new pngs is not a big deal in this case, but if i had more frames, and/or bigger sprites it could make a significant difference in future projects.
I was thinking you could make the animation flip horizontally when it reaches the last fame, however that would mean you would have to omit #4 and #5 to avoid duplicates, but it still would look odd because frame #3 would skip directly back to frame #0. I tried thinking of different orders the sprite frames could be placed in to clean this up, but all my solutions either result in duplicate frames, or ugly skips. Maybe you might be able to solve what I couldn't.
Unfortunately, it seems that though Godot supports play_backwards functionality for the animation_player node, there is no such feature when it comes to animated_sprite. Too bad, because this would likely solve your problem.
For now, I think your best bet is to do what you were trying to avoid.. flip the sprite images yourself and add them as animation frames, or make a separate animation containing the flipped sprites and have them switch back and forth after their last frames, respectively. It might be a lot of work for super large projects, but without some kind of play_backwards functionality for animated sprites, I don't think it's worth breaking your back trying to find a workaround this time.
Of course, if I am wrong, I would welcome any correction from the community.
Good luck.
this is one way to accomplish the task.
Inside the ready function of godot write
#used to store frame value
var frame = 0
Inside the function that your using that runs every frame write:
frame += 1
#resets the value representing the current frame
if frame > 5:
frame = 0
if frame == 4 || frame == 5:
#this should be whatever function you use to flip the sprite vetically
flip_h = true
else:
#this should be whatever function you se to flip the sprite horizontally
flip_h = false
You probably already know this because I recognize the udemy course this screenshot is from, as I am doing it right now, and this is explained later in the course (when adding spikeman enemy). But for those who don't know it can be solved by adding an AnimationPlayer and adding new animation track that deals with animation flip_h property of AnimatedSprite. Then you have to set flip_h on those last 2 duplicated frames.
You could use the signals to detect when the animation has finished
I have a player and a coin. The coin moves towards the player at 400 per pixel, when it collides with the player the player is thrown back. How can I make the player stand still as if nothing had occurred? I tried setting immovable property to player but no result.
Sounds like you want game.physics.arcade.overlap instead of collide. collide will try and separate your sprites; overlap will just let you know that they touched. If you don't do anything in your overlap callback then the sprites will pass right through each other.
I use overlap a lot more than I use collide.
This question already has answers here:
How do I detect collision in pygame?
(5 answers)
Closed last month.
I am having two problems with my code:
I don't know how to make my character check that it's colliding with the blocks
How do I blit to a new screen every time she completes a level? So when the character reaches the stair then a new screen should appear showing the new level
Here is all my code :
http://pastebin.com/u/bluesplay106
I am pretty new to pygame so my style may not be good and I kind of hard coded this game.
If you could tell me how to fix my problem that would be really great!!
for the collision detection you need to make your character and your blocks into sprites and do a collision detection that way.
As for the new screen when you get to the stairs, you can use a statement like this:
if heroSprite_x >= 200 and heroSprite_x <= 300:
if heroSprite_y >= 300 and heroSprite_y <= 400:
#go to new screen using either a new level from a list or a new class or whatever method you want.
Your question was a bit vague but I hope that's what you were looking for :)
I just realized I didnt answer your first question, here's a snippet from one of my games:
unit_enemy = pygame.sprite.groupcollide(unitgroup, enemygroup, True, pygame.sprite.collide_mask)
for hit in unit_enemy:
#do something
This checks if any enemies hit my unit. So in you case it would be your hero, and the enemies would be blocks.
Here's the documentation on collision detection.
http://pygame.org/docs/ref/sprite.html