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.
Related
I have a "Player" scene, which holds everything about a player, the sprite, the animations, the shadow, and a collection of other things.
A script variable 1,2,3,4, etc.. controls which image/texture/sprite data is loaded, to control the appearance.
But when I drop them on the 2D editor, they all have the default image, so they all look identical. Which is confusing. Whats the best way to make each player appear different in the editor?
This code in the player script is good at allowing setting a player number, and loading a different image set, but it doesn't show in the 2D editor. Changing the character number makes the image change at runtime:
export var characterNumber = 1
var player1 = preload("res://Player/Player1.tres")
var player2 = preload("res://Player/Player2.tres")
func _ready():
if characterNumber == 1:
get_node("Sprite").set_texture(player1)
if characterNumber == 2:
get_node("Sprite").set_texture(player2)
Alternatively, I could have multiple sprites in a generic player scene, and turn them on and off depending on the characterNumber, but again, the same problem occurs, the change isn't visible until runtime.
One idea is multiple children scenes, but I cant work out how to turn sprites on or off depending on a variable or some other type of setting.
What am I doing wrong?
In your script your want to make it a 'tool' so it can execute inside your editor, and not only when you launch the game.
see https://docs.godotengine.org/en/stable/tutorials/plugins/running_code_in_the_editor.html
In your case, you might use something like the following: (make sure to do "Scene -> Reload saved scene" to reload the constructor if your change the node's property)... a more ergonomic (but takes more processing) solution is to put it in the _process func
tool
export var characterNumber = 1
var player1 = preload("res://Player/Player1.tres")
var player2 = preload("res://Player/Player2.tres")
func _ready():
if Engine.editor_hint:
if characterNumber == 1:
print("executing custom in editor logic")
if characterNumber == 1:
get_node("Sprite").set_texture(player1)
if characterNumber == 2:
get_node("Sprite").set_texture(player2)
func _process(_delta):
if Engine.editor_hint:
# only rotate the object if we set the character number to 1
if characterNumber == 1:
rotate(Vector3(0,1,0), deg2rad(15*_delta))
set_my_texture() #quick n dirty way for fast reload
func set_my_texture():
if characterNumber == 1:
get_node("Sprite").set_texture(player1)
if characterNumber == 2:
get_node("Sprite").set_texture(player2)
Ryu's approach of using a tool script would work. You can use Engine.editor_hint to identify when your script is running in the editor.
By the way, combine it with setget, so you can define a setter function that will run when you modify the variable. You should not need _process, which would be running every frame.
Anyway, let me cover a few alternatives:
You can make inherited scenes (from the context menu of an existing scene in the FileSystem panel choose "New Inherited Scene"), and there modify it however you want. You can change properties such as the texture of sprites, or you can add other scene instances as children. This solves the problem of placing an instance of a particular variation of your scene, and being able to tell it apart in the editor, without the need to run your script on the editor.
If you have all the textures you want in single atlas/sprite sheet, you can use an AnimatedSprite, except you are not going to use it to animate. Instead put all the textures in a single animation, and then change the frame to pick the texture you want. This gets close to what you want in that you just change a number (the frame).
For completeness I'll also mention that you can use an AtlasTexture to load a texture form an sprite sheet. On the texture of your Sprite (for example), select "New AtlasTexture", then atlas of the AtlasTexture load your sprite sheet, and set region to take the area of the texture atlas you want. I suggest setting the size (width and height of the region) first. This approach will also work for anywhere you might need a texture, although tweaking the region is more work that simply setting a number. By the way, AnimatedTexture can serve a similar role, but it does not give you a way to specify the frame you want.
And yes, you could control any of these form a tool script.
Addendum: by the way, you know you can enable "Editable Children" on the scene instances on the Scene panel, right? It is in the context menu. That lets you edit the instances directly. I wanted to mention it, just in case that helps you.
I'm new to coding in general and I'm trying to make a sprite change texture so it has a walking animation but I can't seem to figure out how to apply a wait() or something to my code.
if Input.is_action_pressed("move_up"):
vel.y -= 1
facingDir = Vector2(0, -1)
$LilBoiTexture.texture = load("res://LilBoiAssets/LilBoiBackward.png")
$LilBoiTexture.texture = load("res://LilBoiAssets/LilBoiBackward2.png")
Any help is appreciated. I'm trying to change from the first texture to the second one within idk 0.5, or something ill mess with it if i can figure out what to do.
There is an easier way of doing this instead of changing sprite image manually. You can use "AnimatedSprite" node as shown in the tutorial. Here are the steps:
1- Add an AnimatedSprite node to your character.
2- In properties of AnimatedSprite, Frames-> select new SpriteFrames.
3- Click SpriteFrames you just created, another menu will appear at the bottom of editor. Drag and drop your animation images to center of this menu.
4- Change animation name from default to something else (for example walkback).
5- In your code you just need to do this:
if Input.is_action_pressed("move_up"):
$AnimatedSprite.play("walkback")
else:
# you can also play an idle animation if you have one
$AnimatedSprite.stop()
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 new to Unity and I started with the Catch Game Tutorial to learn to create a 2D game. Everything is working now but for my needs, I would like to add different textboxes to each of the fallen elements (in the tutorial the bowling balls) Those texts should move with the objects. I know I can change text dynamically in the code, but I couldn't figure out how to correctly add the element.
I tried to add a text object as a child of the gameobject and also tried to create a new gameobject which contains a text, but I can't position the element in front of the background and above my wished element (I can't choose a sorting layer for this)
Imagine this is the object which has to be collected and I would like to show a text like this:
My Questions are:
1. How can I add a text to be displayed in the correct position (GUIText, text in a gameobject, only text or something else?
2. How can I make this text dynamically move with the fallen object?
3. Can I set a background to my text as displayed above?
Thank you in advance!
I found a solution for my problem and did the following thing:
I created a Sprite with my wished background (black rectangle) and added it to the scene
I created a 3D Text and added it as a child to the created Sprite (and scaled it and positioned it)
I added a Script to the 3d Text with the following content:
void Start () {
this.gameObject.GetComponent<Renderer>().sortingLayerName = "[MyLayerName]";
this.gameObject.GetComponent<Renderer>().sortingOrder = 3;
}
I added the Sprite (with the text as child) to my gameObject (ananas)
A renewed the object in the Prefabs folder
Maybe my solution helps other people facing a similar problem.
I'm writing a video player with two QGLWidgets -- a controller(a menu with buttons like select, play) and a viewer(where the video actually gets played). For the viewer, I have the paintGL function calling the display function I implemented to update each frame. But unless I resize the viewer window or switch between the two windows, the viewer doesn't update itself and just stops on the third frame.
In other post, I found that I have very little control over when paintGL gets called (resizing is one of the cases where it gets called). Is there a way to work around the this?
Thanks!
Edited:
So I have two classes: Player and Viewer (both QGLWidgets)
When running the program, a player (the controller) will be displayed, and users can choose a video and hit the play button. The player handles the play button in the way that it creates a Viewer which plays the selected video.
def handlePlayButton(self):
self.viewer = Viewer(self.filepath)
self.viewer.show()
And the Viewer is initialized and updated as following
def paintGL(self):
self.display() //update the window with the current frame
glViewport(0, 0, self.vid.getWidth(), self.vid.getHeight())
def resizeGL(self, w, h):
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
def initializeGL(self):
//initialize the shaders with other libraries