I'm trying to instantiate a UI image in unity 5 to display a players health. I've used a for loop to spawn a new health block image for every 10 health the player has remaining. However, I can't get the image to actually show on screen (it works when I set up the prefab, but as soon as I try to instantiate it through the code it vanishes). The code isn't finished yet as at the moment I understand all the images will stack on top of each other rather than in a row (which will be the finished result) but I want to make sure I can get the images to actually show first before taking this further. Any help would be appreciated!
Things to know:
Player health is set to 100,
Health per icon is set to 10,
I'm using a prefab (health that only contains a UI image component within my canvas.
code:
using UnityEngine.UI;
public class GameController : MonoBehaviour {
public GameObject player;
public int playerStartingHealth;
public Image healthBarGreen;
public int healthPerIcon;
void Start () {
score = 0;
UpdateScore ();
AddPlayerHealth (playerStartingHealth / healthPerIcon);
StartCoroutine (spawnWaves ());
}
public void AddPlayerHealth (int n) {
for (int i =0; i < n; i++) {
Instantiate(healthBarGreen.gameObject);
}
}
}
Bit of a necro, but this post is high on a google search on the subject. Solution:
Image newImage = Instantiate(prefabImage, Vector3.zero, Quaternion.identity);
newImage.transform.SetParent(canvas.transform, false);
newImage.rectTransform.anchoredPosition = Vector3.zero; // your new position here
Related
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MakePipe : MonoBehaviour
{
public GameObject pipe;
float timer = 0;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
timer += Time.deltaTime;
if (timer > 1)
{
Instantiate(pipe);
timer = 0;
}
}
}
I am trying to instantiate pipes using prefab, and with the code, a new set of pipes should spawn and move left from the original position where the first set of pipes spawned, but they are not visible.
They are generated as clones in the hierarchy, but when I double-click them to check the position, it points towards the first pipe position.
My guess is that new clones are generated and overlapped in the first pipe as they move together.
Please help
Thanks for your reply.
Sorry I didn't add a separate cs code 'move', I should have added gif..
The following code is to move the pipe left with certain speed. There is no problem there.
However from the 'MakePipe' code that I originally posted, I used instantiate to keep reproducing the pipe. Maybe I should add some lines to 'Start()' part to set original spawn location?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move : MonoBehaviour
{
public float speed;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
transform.position += Vector3.left * speed * Time.deltaTime;
// Debug.Log(transform.position);
}
}
I had to delete photos because error message tells me I should have more than 10 reps to edit :(
I don't have enough rep to comment, I'll attempt to give you a answer and update it for what you need.
The Object.Instantiate method has some parameters that you can use to get your pipes into place.
public static Object Instantiate(Object original, Vector3 position, Quaternion rotation, Transform parent);
And without the overloads it will use the original prefab's parameters. So they will spawn in the same location. You have to calculate the next position and pass it in the Instantiate method (Vector3 position).
I misunderstood what you are trying to do at first. #Geeky Quentin
gave the right answer in the first comment.
[SerializeField] private GameObject pipe;
float timer = 0;
float offset = 1.5f;
void Start()
{
}
void Update()
{
timer += Time.deltaTime;
transform.position += new Vector3(-Time.deltaTime/offset, 0, 0);
if (timer > 1)
{
GameObject lastPipe = Instantiate(pipe);
lastPipe.transform.SetParent(transform);
timer = 0;
}
}
I still don't have enough rep to comment. Regarding your last changes. I tested your code out.
Are you parenting the instantiated pipe to the PipeMaker in another script? If not this is the effect it spawns but it does not move:
To make it work you need to parent the instantiated pipe and change it's position MakePipe.cs:
public GameObject pipe;
float timer = 0;
private GameObject _newPipe;
void Update()
{
timer += Time.deltaTime;
if (timer > 1)
{
//instatiate with parent on transform
_newPipe = Instantiate(pipe, transform);
//Set positiion to orginal prefab position
_newPipe.transform.position = pipe.transform.position;
timer = 0;
}
}
This is the effect:
My PipeSpawner has the Move and MakePipe scripts attached to it. And the prefab is in a hidden PipePrefab object that's unrelated to the rest of the system.
You could also set the position of the original spawn location in your Start() method as you said, it's up to you.
So I'm making a zombie shooter game that works well, but after running for a while I get hit with this exception:
Exception in thread "LWJGL Application" com.badlogic.gdx.utils.GdxRuntimeException:
Couldn't load file: 1zom3.png
at com.badlogic.gdx.graphics.Pixmap.<init>(Pixmap.java:140)
at com.badlogic.gdx.graphics.TextureData$Factory.loadFromFile(TextureData.java:98)
at com.badlogic.gdx.graphics.Texture.<init>(Texture.java:100)
at com.badlogic.gdx.graphics.Texture.<init>(Texture.java:92)
at com.lastride.game.Entity.changeState(Entity.java:51)
at com.lastride.game.Enemy.seek(Enemy.java:39)
at com.lastride.game.LastRideGame.update(LastRideGame.java:149)
at com.lastride.game.LastRideGame.render(LastRideGame.java:229)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:215)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:120)
Caused by: java.io.IOException: Error loading pixmap:
at com.badlogic.gdx.graphics.g2d.Gdx2DPixmap.<init>(Gdx2DPixmap.java:57)
at com.badlogic.gdx.graphics.Pixmap.<init>(Pixmap.java:138)
... 9 more
I know for a fact that the image is there as it works, but it seems that after running for a bit it crashes.
This is the method where it crashes on:
public void changeState(int i)
{
//changes the state and concurrently the image associated with the given state
state = i;
sprite = new Sprite(new Texture(Gdx.files.internal(name+i+suff)));//crashes here
bounding = (sprite.getBoundingRectangle());
if (sprite.getTexture().getTextureData().isPrepared()==false)
{
sprite.getTexture().getTextureData().prepare();
}
playerMap = sprite.getTexture().getTextureData().consumePixmap();
}
As #Tenfour04 points out, it could be an out-of-memory problem.
Instead of doing this:
sprite = new Sprite(new Texture(Gdx.files.internal(name+i+suff)));
Create an global (and/or possible static and/or possible final) Texture object, and load it just once at the beginning of your game and use it repeatably.
Something like this:
public static Texture myTexture_1; //<< your texture
public static final int ID_MY_TEXTURE_1 = 1; //<< this will work as an ID
// This method is called once in your game (like in the create() method)...
public static void load() {
myTexture_1 = new Texture(Gdx.files.internal(name + ID_MY_TEXTURE_1 + suff));
}
// when no longer necessary, remove it...
public static void dispose() {
myTexture_1.dispose();
// and so on...
}
then, in your changeState() method, do a switch to retrieve the correct texture:
public void changeState(int i) {
state = i;
switch(i){
case ID_MY_TEXTURE_1 :
sprite = new Sprite(myTexture_1);
break;
// rest of cases...
}
// rest of your code...
}
I'd like to animate my Score-GUI text counting up to a variable value but there are two things in my way:
1: How can I animate to a variable instead of a fixed value?
2: Why can't I add own properties (like int) to my script and animate them?
For #2 I created a property in my script. Yet the editor won't show it in the AddProperty-dialog (as shown below):
public int currentScore = 0;
public int score {
get { return currentScore; }
set { this.currentScore += value; }
}
EDIT: The animator is set up in the most basic way:
Since you only have 1 Animation. An Animator is irrelevant to the solution. This is tested and working. Now you need to make the Animation a Legacy type to get this working because we are not going to use the Animator.
Click the Animation on the Project -> look at the upper right section of the Inspector view, there is a little button there which will drop down a selection. "Debug" then Check the Legacy.
Set your Animation to whatever you want. I force the WrapMode in the script to be wrap mode once. So it will only play once.
Now in the Animation Component make sure you select the Animation that you want by default or it wont work. Cause we only use anim.Play(); Without parameters meaning, run the default animation that is set.
I created a Text UI and added an Animation that alpha is 0 from the start and at the end point making it 1. You have to do that on your own.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class MyScore : MonoBehaviour {
// Use this for initialization
public int currentScore = 0;
public GameObject Myscore; // Drag the GameObject that has the Animation for your score.
public Text myScoreText; //Drag in the Inspector the Text object to reference
public Animation anim;
public int score
{
get { return currentScore; }
set { this.currentScore += value; }
}
void Start()
{
anim = Myscore.GetComponent<Animation>(); // Reference the Animation Component.
anim.wrapMode = WrapMode.Once; // Legacy animation Set to play once
AddScore();
}
public void AddScore()
{
score += 10;
myScoreText.text = score.ToString();
anim.Play();
Debug.Log("Current Score is "+ score);
Invoke("AddScore", 2);
}
}
Good luck.
I am using libGdx to code a Pong-like game.
In the GameScreen I want to display the remaining lives of each player.
For that, in the create() of the GameScreen I have a table containing several ImageButtons:
for(int i = 0; i < lifePlayer1; i++){
lives[i] = new ImageButton(skin, "Life");
lifeTable.add(lives[i]);
lives[i].setVisible(true);
lives[i].setTouchable(Touchable.disabled);
}
Each ImageButton represent a life. When a player loses a life, the ImageButton corresponding to the lost life is setChecked, and the imageChecked represents the lost life
Before the game start I want to display a message saying "Game Starts !". The message crosses the screen from left to right, and the game starts only when the message has disappeared.
The problem I encounter is that the instantiation of the lifeTable takes time, and the GameScreen starts running before the instantiation is finished. I explain :
When I disable the lifeTable, everything runs smoothly, the "Game Starts !" message crosses the screen from left to right and the game starts.
When I enable the lifeTable, when I press on the "New Game" button in my MainMenueScreen, there is a delay (let's say 0.5 seconds), like a loading time, and when the GameScreen is finally displayed, the "Game Starts !" message has almost finished crossing the screen.
I have a 2 players mode, with 2 lifeTable to load, and it's even worse, when the GameScreen displays, in 2 players mode, the "Game Starts !" message has already finished crossing the screen and the game has already started.
I am using an AssetManager, and every texture used in the game are already loaded before reaching the MainMenuScreen. The AssetManager helped to reduce the GameScreen loading time, but it's still not satisfying.
Is there something to preload the lifeTable, the same way we preload the textures with the AssetManager ?
Or, is there a way to have the render() of the GameScreen starts only when the create() has finished the instantiation of ever objects ?
Thank you for your help.
is probably not the most efficient way to make but which occurred to me while reading your question, and it is simple
Variable Class
private boolean loadForTest = false;
.
#Override
public void show() {
.//Other Code
image = new Image(YourAssetManager.get("YourImage.png", Texture.class));
image.addAction(Actions.sequence(
Actions.moveTo(Gdx.graphics.getWidth(),
(Gdx.graphics.getHeight()/2),
1f)));
image.setPosition((-100f), Gdx.graphics.getHeight()/2);
YourStage.addActor(image);
}
#Override
public void render(float delta) {
.//Other Code
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
if (loadForTest == false){
if (image.getActions().size == 0){
Gdx.app.log("test" ,"now load table");
for (int i = 0; i <lifePlayer1; i ++) {
vidas [i] = new ImageButton (piel, "Life");
lifeTable.add(lives[i]);
lives[i].setVisible(true);
lives[i].setTouchable(Touchable.disabled);
}
loadForTest = true;
}else{
Gdx.app.log("test" ,"Your Other Code Play");
}
}
}
Edit
added another code because my English is not very good and did not know very well what you wanted to do
Variable Class
private boolean loadForTest = false;
.
#Override
public void render(float delta) {
.//Other Code
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
if (loadForTest == false){
for (int i = 0; i <lifePlayer1; i ++) {
vidas [i] = new ImageButton (piel, "Life");
lifeTable.add(lives[i]);
lives[i].setVisible(true);
lives[i].setTouchable(Touchable.disabled);
}
loadForTest = true;
}else{
Gdx.app.log("test" ,"Your Image load, Your Other Code Play");
}
}
How to display images in the form of pages where only one page is displayed at a time on blackberry screen. On scrolling down subsequent images will load at run time. So that loading of images do not consume time at startup.
Edit: I am using loadimage function which loads images from blackberry device memory which loads images from specified path and resizing them.As number of images increases, it increases the startup time during opening of window.There is an in-built application(Media) in blackberry phone, where images load without taking any extra time. My idea is to display particular number of images which fit to the blackberry screen. As user scroll down to bottom of screen, application will then load and display more images. So my question is how to detect when user reached to bottom of blackberry screen and display one more row images.
Keep array of images url and current image index. Put a BitmapField on screen. Add menu items for Next/Prev. On Next load Bitmap from incremented index url, set it to BitmapField and invalidate screen. On Prev do the same with decremented index.
you can use button as well (maybe in storm) but menu is obligatory
load images in separate threads (especially if they are stored in web)
you can implement caching (in app memory or by saving images on device storage)
some text field may be helpful (file name, type, size, dimentions etc)
UPDATE
For this purpose you can use ScrollChangeListener
try this code:
class Scr extends MainScreen implements ScrollChangeListener {
static int mRowNumber = 0;
public Scr() {
getMainManager().setScrollListener(this);
//preload some images on the start
for (int i = 0; i < 20; i++) {
mRowNumber = i;
add(new BitmapField(downloadBitmap(), FOCUSABLE));
}
}
public static Bitmap downloadBitmap() {
Bitmap result = new Bitmap(200, 80);
Graphics g = new Graphics(result);
g.drawRect(0, 0, 200, 80);
g.drawText("row #" + String.valueOf(mRowNumber), 30, 30);
return result;
}
public void scrollChanged(final Manager manager, int newHorizontalScroll,
int newVerticalScroll) {
int testBottomScroll = manager.getVirtualHeight()
- manager.getVisibleHeight();
if (testBottomScroll == newVerticalScroll) {
mRowNumber++;
(new Thread(new Runnable() {
public void run() {
// simulating download
Bitmap bitmap = downloadBitmap();
// update ui in thread safe way
addBitmap(bitmap);
}
})).start();
}
}
public void addBitmap(final Bitmap bitmap) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
getMainManager().add(new BitmapField(bitmap, FOCUSABLE));
}
});
}
}
PS the problem with this approach is you will be able to catch scroll event only if there are enough images on screen. Consider using Screen.navigationMovement(int, int, int, int) then. And don't forget to test it with trackwheel and touchscreen.
Btw my opinion is that it would be better to load all images at once using some thread queue (so images will be loaded asynchronously without locking ui)