I'm a newbie, and I'm working on a game using Godot.
I'm making a game called "Pong", I'm creating a winning scene when one player reaches 5 points.
Here is my code:
if self.score1 >= winning_score or self.score2 >= winning_score:
get_tree().change_scene("res://compWin.tscn")
The code works in changing scene but after the scene is changed, the last scene which is the game still keep running. How can I fix it?
I am unable to recreate this bug using your code, everything goes smoothly and the scene before compWin never ran in the background like you described. This error could be caused by other code.
Related
Here is my code: (just so you know I am a beginner and I just started this week, though I do have knowledge with other languages and game engines)
func _on_Area2D_area_entered(area):
get_parent().get_node("Level 1/Area2D/Flag").rotation_degrees += 1
What I was trying to accomplish was that the Player GameObject would see if its in the area of the Flag, and if it is, the flag would rotate.
I am not sure where the issue is. I think it is probably in the second line. I provided a screenshot below if I did the setup wrong. I have looked at the other close questions asked on the same topic, but they did not answer my question.
The "Player" GameObject is the one with the script that contains the detection if its in the area2D.
If you want to check if the Area2D is positioned correctly during runtime enable Debug -> Visible Collision Shapes.
If you want to check if _on_Area2D_area_entered is running, add breakpoints (or use print).
Did you get an error?
If there isn't a Node there, this expression will cause an error in runtime:
get_parent().get_node("Level 1/Area2D/Flag")
If you want to be able to check, you can use get_node_or_null and is_instance_valid.
Since you didn't mention any error, I'm going to guess the method is not running.
If the method is not running, the most likely culprit is that - I'm guessing given then name of the method - you connected the "area_entered" signal but intended to connect the "body_entered" signal.
The "area_entered" signal will trigger when another Area2D enters the Area2D. But I only see one Area2D in your scene tree. On the other hand the "body_entered" will trigger when a PhysicsBody2D (e.g StaticBody2D, KinematicBody2D, RigidBody2D) enters the Area2D. In either case you get what entered as a parameter of the method.
Other reasons why the Area2D might not be detecting what you want include no intersection of collision_layer and collision_mask and monitoring being disabled.
And to dismiss a couple possible misconceptions:
The "area_entered" and "body_entered" trigger when the Area2D or PhysicsBody2D respectively enter the Area2D, not every frame they are inside. So rotation_degrees += 1 is not a rotation animation.
You will get notifications of anything that trigger the signals, not just the object to which you connected it. You may have to further filter, e.g. if body == self:.
For people arriving here from search, I want to link a similar case: Enemy is not affected by bullets. And also my full explanation of how to set up physic nodes.
I am trying to learn how to build a simple platform game with Phaser, but I am having trouble getting the player to jump.
I can see that it is detecting when the "up" button is being pressed, but for some reason the player does not move. My jump code is identical to other examples I have seen, so I am assuming the problem is elsewhere in the file. Do I perhaps need to change the player's gravity or something? I was also wondering if it could be because the game thinks the player is colliding with a wall?
Here is a codepen:
https://codepen.io/moorehannah/pen/RXRroK
and this is the specific code for the jump:
if (this.cursor.up.isDown && this.player.body.onFloor) {
this.player.body.velocity.y = -320;
console.log("up");
}
The tutorial I followed is this one:
http://www.lessmilk.com/tutorial/2d-platformer-phaser
Any help would be greatly appreciated!
The gravity may be too high. You could see if changing onFloor to standing works, or you could even use this.player.body.blocked.down
I'm new to Phaser3 and before starting a crazy project, I want to know how I should start, switch between scenes. I saw that there are several functions, start, launch, switch, run, resume, pause, etc.
Example, lets say I want to have 2 scenes, a Menu and a Game. I boot on the Menu and I want to go to the Game scene and if I click on a button then come back to the Menu scene.
I've achieved this by calling the start function, but I noticed that the all, init, preload and create functions are called every time and therefore I'm loading all the images, setting all the listener over and over again.
This seems wrong, should I be using the launch or switch functions and pausing and resuming? But how do I hide the previous scene?
Thanks in advance.
This question might be a little too broad, but with Phaser 3 in mind, it still depends upon what purpose your menu serves.
I think most games have a main menu that will generally be called when the game first starts, and then won't be called again.
If this is an in-game menu, where settings can be changed or part of the game can be reset/restarted, then it might not make sense to redirect to a completely different scene.
With Phaser 3's support of multiple scenes - with Dev Log #119 and Dev Log #121 probably being the best current sources of information - another option would be to start a new scene within the current scene to handle this.
However, if this is really just UI, there's nothing to stop you from creating an overlay, instead of spawning an entire scene.
If you're concerned about performance I might think about whether the entire menu needs to be called, or if a simplified menu would work. Also, make sure that you're preloading assets before you're in the menu and main game.
I personally use Boot > Preloader > Splash Screen > Main Menu > Main Game scenes, where the Preloader loads the majority of the assets I'll need. This has the downside of a longer initial load, but the upside of minimal loading after this point.
Scene Transitions
How I handle these in my starter templates is to add the scenes to the Scene Manager when creating the scene. Then I transition by start to the first scene.
this.scene.add(Boot.Name, Boot);
this.scene.add(Preloader.Name, Preloader);
this.scene.add(SplashScreen.Name, SplashScreen);
this.scene.add(MainMenu.Name, MainMenu);
this.scene.start(Boot.Name);
Then I simply keep starting the next scenes as needed.
this.scene.start(Preloader.Name);
For another game that uses multiple scenes I ended up creating the following function (TypeScript) to handle this:
private sleepPreviousParallelScene(sceneToStart: string): Phaser.Scene {
if (this.uiSceneRunning !== sceneToStart) {
// Make sure that we properly handle the initial state, when no scene is set as running yet.
if (this.uiSceneRunning !== "") {
this.scene.get(this.uiSceneRunning).scene.sleep();
}
const newScene = this.scene.get(sceneToStart);
newScene.scene.start();
this.scene.bringToTop(sceneToStart);
this.uiSceneRunning = sceneToStart;
return newScene;
} else {
return this.scene.get(this.uiSceneRunning);
}
}
In the game I was using this for, I was trying to replicate a standard tab interface (like what's see in the Dev Logs above with the file folder-like interface).
Ok, here is the deal. In phaser 3, the start function actually SHUTS DOWN the previous scene as it starts the new one. This is why you see the init, preload ext every time. If however, you 'launch' your scenes instead, then they will not go through the whole shut down, restart sequence. You can move them to the top or bottom, set to receive input or not, etc. HOWEVER, BEWARE! As of phaser 3.16, sleep or pause of a scene does NOT shut down the update. As a result, if you launch a scene, then sleep it, it basically does nothing other than maybe set the flag, saying it's asleep even though it really isn't. So any update processing will continue in any launched scene. You can short circuit the update with a flag of some sort at the beginning, (that's what I've resorted to), but the other gotcha is the camera size. All the scenes must therefore have the same camera size or they will render (even if "sleeping") and mess up your display.
So, bottom line, it's going to be messy until sleep and pause actually work.
I'm working on the UI for a tower defense game for my university's video game development club using Godot. I have code to drag towers from the menu onto the board, but it's not working properly. I've tested it in a separate file and it works fine, but as soon as I run it in the actual program, which has the turrets in a GridContainer, it stops working. Each turret is a TextureRect currently, all of which are children of a GridContainer, which itself is a child of another TextureRect which is the background. Finally, the root of the scene is a MarginContainer.
Here's the code. It's basically just the official drag and drop demo but modified for TextureRects.
extends TextureRect
func get_drag_data(pos):
var prev = TextureRect.new()
prev.texture = texture
prev.rect_size = Vector2(50,50)
set_drag_preview(prev)
return texture
func can_drop_data(pos, data):
return true
func drop_data(pos, data):
texture = data
So my question is, how can I make drag and drop work when the things that get dragged are in a container? I could do this without containers, but that sounds like it would lead to some bad UI design so I'd really rather not.
Ok I am a complete noob to pygame and programming in general. However I have been working on a game where the player falls and dodges objects. The idea is that the player remains within the top 1/4 of the screen and everything scrolls upwards to give the illusion of moving. This works fine however the code below is where I try and get another wall to spawn. This should work by deleting the sprite when it goes off the screen and spawning a new sprite when the image starts to go off the screen. The -2 is how far it should cross until another is spawned and my logic was to check the size of the group. While it only contained one it would iterate through the next section of code defining a new wall sprite identical to the old one but positioned below it. However this causes the program to crash probably because the old sprite is deleted causing an infinite loop. So if this is true how do you define a new sprite with the same attribute whilst not killing the other?
Also I realised that the code wont even work multiple times because I used "left_wall" which wont be defined after its been deleted so I tried using "wall" as I iterate through the group defining each sprite as wall in the for loop so every time a new wall is added it should be defined as wall so that I works infinitely. however I this error message AttributeError: 'Game' object has no attribute 'wall'. So at this moment I am stuck, not really knowing what to do next.
edit: I forgot to take off "self" when using "wall" which was the cause of the attribute error however it is still crashing like I mentioned in the first paragraph which is probably due to the old sprite being deleted.
sorry if this is confusing or not a properly structured question (like I said, I am a noob).
for wall in self.left_wall_sprite:
wall.rect.y -= self.player.vel.y
if wall.rect.bottom < 0: # move left wall
wall.kill()
if wall.rect.top == -2: # a new wall needs to be spawned
while len(self.left_wall_sprite) < 2:
self.new_left_wall = self.left_wall
self.new_left_wall.rect.top = self.left_wall.rect.bottom
self.all_sprites.add(self.new_left_wall)
self.left_wall_sprite.add(self.new_left_wall) # add the new sprite to the wall group so that it runs through the same cycle
With only this part of the code, it is hard to tell for sure what is going on - but what can be detected is that you create a new wall section, but do not "leave things as you found them" - so, that the code will still try to move the old wall.
If you really need to create a new sprite, go all the way: once the condition is met for the change:
get a reference to the old wall
remove the old wall from all groups (the .kill method)
create a new wall (create a new instance - you are just making an
assigment to an existing instance).
insert the new instance in all relevant groups.
As the code is, you are just pointing to the same wall object (self.left_wall) so that "self.let_wall" and "self.new_let_wall" are just references to the samething, and when you change a parameter (like rect.top) in one side, you can see the same change in the other.
Without the code for the class of your wall objects, one can't now if everything is set for correctly creating a new instance, but that could typically be done by self.left_wall = Wall((wall.rect.bottom, wall.rect.left, wall.rect.width, wall.rect.height)) (if your class's __init__ will take a rect as first parameter). This replaces the old self.rect_wall (which should have a reference on the wall variable yet) - you then just add it to the new groups.
But it looks like you can just reuse the same sprite - so, jsut update the top coordinate as you are doing -no need to fiddle with group containment or anythng:
if wall.rect.bottom <= 0:
wall.rect.top = wall.rect.bottom # or "0" at once