I´m using Scene2D and I have a ball. this ball is an actor and it does an action when the ball hit the rectangle, and when the action finished the ball continue moving arround the screen.
But I want that when the ball hit the rectangle again it do the action again, but i don´t know how do it.
Code:`private void muerte() {
if(choque){
System.out.println("choque");
velocidadbolax=0;
velocidadbolay=0;
//bola.addAction(a1);
bola.addAction(Actions.sequence(a1, Actions.run(new Runnable() {
public void run () {
velocidadbolax=95;
velocidadbolay=30;
}
})));
}
}
Choque is a boolean of the colision. When the colision happened the ball stoped, and the action start, then,when the action finished, the ball move.
You can add action to actor in the same way as you do this when you detect first collision.
actor.addAction(sequence(fadeIn(2), run(new Runnable() {
public void run () {
System.out.println("Action complete!");
}
})));
Thre you can find more info: https://github.com/libgdx/libgdx/wiki/Scene2d
Related
I have a gameObject called BounceBack that is supposed to bounce the ball back far away when they collide together.
public class BounceBack : MonoBehaviour
{
public GameObject Player;
public float force;
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag(Player.tag))
{
Player.GetComponent<PlayerController>().ForceBack(force);
}
}
}
The ball Player (ball) script:
public class PlayerController : MonoBehaviour
{
public int acceleration;
public int speedLimit;
public int sideSpeed;
public Text countText;
public Text winText;
public GameObject pickUp;
public GameObject finishLine;
//internal void ForceBack() //Not sure what it does and why it's there.
//{
// throw new NotImplementedException();
//}
private int count;
private Rigidbody rb;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
SetCount();
}
// Update is called once per frame
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal") * sideSpeed * rb.velocity.magnitude / acceleration;
//float moveVertical = Input.GetAxis("Vertical") * acceleration;
if (rb.velocity.magnitude <= speedLimit)
{
rb.AddForce(0.0f, 0.0f, acceleration); // add vertical force
}
rb.AddForce(moveHorizontal, 0.0f, 0.0f); // add horizontal force
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag(pickUp.tag))
{
other.GetComponent<Rotate>().Disapear();
count++;
SetCount();
}
if (other.gameObject.CompareTag(finishLine.tag))
{
acceleration = 0;
sideSpeed = 0;
finishLine.GetComponent<GameEnd>().FadeOut();
if (count >= 2)
{
winText.GetComponent<WinTextFadeIn>().FadeIn("Vous avez remporté la partie!");
}
else
{
winText.GetComponent<WinTextFadeIn>().FadeIn("Vous avez perdu. Réesayer?");
}
}
}
private void SetCount()
{
countText.text = "Count : " + count.ToString();
}
public void ForceBack(float force)
{
Rigidbody rb = GetComponent<Rigidbody>();
rb.AddForce(0.0f, 0.0f, -force, ForceMode.VelocityChange);
Debug.Log("Pass");
}
}
The AddForce function does not do anything. I tried with setActive(false) and it's not working either. The only thing that works is Debug.Log(). I'm not sure if the speedlimit and acceleration are interfering with the function.
EDIT: I'm not sure if the problem is from Unity but I can't access any variable of the class from the forceBack function inside the class.
EDIT2: I also tried to call the AddForce function directly in the Bounce Back script but it's not working either.
Player.GetComponent<Rigidbody>().AddForce(0.0f, 0.0f, -force, ForceMode.VelocityChange);
Player (Ball) Screenshot
Bounce Back Screenshot
So, a couple things:
1.) The physics system should already cause the ball to bounce if you've set up the colliders and rigidbodies properly. You should only need to do something like this if the ball should gain momentum when it bounces, which is unlikely. You should post screenshots of their inspectors if this answer doesn't help.
2.) On your rb.AddForce() call, you're applying a force in world-space, which may be the wrong direction to bounce. If you know the ball is oriented the way it's moving, then you can call AddRelativeForce with the same parameters. If the ball's orientation is not controlled, then you need to calculate the correct world-space direction to use before applying the force.
3.) Finally, just to confirm, the objects with BounceBack attached do have a non-zero value in the 'force' parameter in the inspector, right?
I want to implement falling leaves in my game in particular intervals.
After 10 seconds of game starts,leaves has to fall.Then again leaves has to fall after 20 seconds and so on.
I have this method for the falling leaves of array;
private void updateFalls(float delta) {
for (Leaf l : leaves) {
l.moveLeavesDown(delta);
}
spawnleaves();
}
Is it possible to do with timer class?Is it possible to call this method inside timer with fixed intervals?
Any help would be appreciated.
You can use Timer in this way :
Timer timer=new Timer();
timer.scheduleTask(new Timer.Task() {
#Override
public void run() {
spawnLeaf();
}
},10,20); // --> 10 is your first delay and 20 is interval in sec.
I'm considering Leaf as a Sprite but it may be an Image or any other Entity.
Here is my spawnLeaf method :
Array<Sprite> leaves=new Array<Sprite>();
private void spawnLeaf(){
Sprite sprite=new Sprite(texture);
sprite.setPosition(MathUtils.random(Gdx.graphics.getWidth()),Gdx.graphics.getHeight());
leaves.add(sprite);
}
Draw and position update part of all leaves
spriteBatch.begin();
Iterator<Sprite> iter = leaves.iterator();
while (iter.hasNext()) {
Sprite spr = iter.next();
spr.draw(spriteBatch);
spr.setY(spr.getY()-50f*Gdx.graphics.getDeltaTime());
if (spr.getY()<0) {
iter.remove();
}
}
spriteBatch.end();
Timer has clear() and stop() method that help in removing all scheduled tasks and stops the timer respectively that may start again.
I am working on my second app and it went quite well so far. But now I got stuch on a problem I just can´t manage to find a solution for.
I´ve been using scene2d stage to display everything. Now I´ve added a black image which fades out whenever a new Screen is called(as a transition).
My problem is, that when I add the fade out action to my black Image it also fades out the background. Interestingly only the background is affected, no other Actor what so ever.
I´ve tried changing the order of the Actors, putting them into groups, clearing all actions from the background, setting his alpha to 1 but nothing worked.
Thanks for helping me !
For the background:
public class BackgroundColor extends Actor {
public BackgroundColor(int x) {
this.setBounds(x, 0, 270, 960);
}
public void act(float delta) {
}
public void draw(Batch batch, float alpha) {
batch.draw(image, this.getX(), this.getY(), this.getWidth(), this.getHeight());
}
}
For the screen:
public class GameScreen implements Screen {
public Stage stage;
public BackgroundColor backgroundColor;
public Image black;
public GameScreen() {
stage = new Stage(new ExtendViewport(540, 900, 540, 960));
Gdx.input.setInputProcessor(stage);
setupStage();
}
private void setupStage() {
backgroundColor = new BackgroundColor(0);
stage.addActor(backgroundColor);
//this is the black layer
black = new Image(AssetLoader.black);
black.setBounds(0, 0, stage.getWidth(), stage.getHeight());
stage.addActor(black);
black.addAction(Actions.sequence(Actions.fadeOut((float)0.5), Actions.touchable(null)));
}
#Override
public void show() {
}
#Override
public void render(float deltaTime) {
Gdx.gl.glClear(0);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
So, I kinda figured it out...
apparently having a different Image as the first layer of the stage solves the issue.
I added in a random Image before the backgroundColor = new BackgroundColor(0); and that fixed it.
I still have no Idea what causes this, maybe I missed something...
Would be great if you could tell me what is going on here!
Cheers
Hi guys so I created a simple game with a flying helicopter in which you need to dodge the missiles. I want to remove all missiles that are created in the screen if gameOver boolean is true. What is happening is it's only removed if the helicopter dies because of hitting the missile, but if it dies by hitting the ground the "game over" message shows but the missiles are not removed!
I tried using
if(heliR.overlaps(missiles)){gameOver=true; Iter.remove; }
But like what I said all missiles are only removed if I died by hitting missile, can anyone help me in this?
Here is my code:
#Override
public void create()
{
batch = new SpriteBatch();
camera=new OrthographicCamera();
camera.setToOrtho(false,800,480);
restart=TimeUtils.nanoTime();
click=TimeUtils.nanoTime();
//fonts
font=new BitmapFont();
font1=new BitmapFont();
font2=new BitmapFont();
font.setColor(Color.RED);
font1.setColor(Color.BLACK);
font2.setColor(Color.WHITE);
font.setScale(3);
font1.setScale(1);
font2.setScale(2);
//score
points=0;
lastScore=TimeUtils.nanoTime();
//background
Texture texture=new Texture(Gdx.files.internal("background.png"));
background=new TextureRegion(texture,0,0,800,480);
//logo
logo=new Texture(Gdx.files.internal("logo.png"));
logoR=new Rectangle();
logoR.x=230;
logoR.y=240;
logoR.width=230;
logoR.height=100;
//helicopter
heli=new Texture(Gdx.files.internal("helicopter.png"));
heliR=new Rectangle();
heliR.x=280;
heliR.y=400;
heliR.width=heli.getWidth()-15;
heliR.height=heli.getHeight()-15;
//Sounds
heliSound=Gdx.audio.newSound(Gdx.files.internal("helicopter.wav"));
heliLanding=Gdx.audio.newSound(Gdx.files.internal("helicopter_landing.wav"));
collision=Gdx.audio.newSound(Gdx.files.internal("collision.wav"));
//missile
missileImg=new Texture(Gdx.files.internal("missile.png"));
missiles=new Array<Rectangle>();
}
public void spawnMissile(){
Rectangle missile=new Rectangle();
missile.y=MathUtils.random(60,400);
missile.x=mX;
missile.width=missileImg.getWidth()-15;
missile.height=missileImg.getHeight()-10;
missiles.add(missile);
lastMissile=TimeUtils.nanoTime();
velocity=250;
}
#Override
public void render()
{
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
batch.begin();
batch.draw(background,backGroundX-800,0,800,480);
batch.draw(background,backGroundX,0,800,480);
batch.draw(heli,heliR.x,heliR.y);
if(justStart==false && gameOver==false){
font2.draw(batch,"Points:"+points,345,480);}
//missile
for(Rectangle missile: missiles){
batch.draw(missileImg,missile.x,missile.y);
}
//game over
if(gameOver==true){
heliR.y=250;
heliR.x=330;
font.draw(batch,"Game Over",280,400);
font1.draw(batch,"[Long press on the screen to restart]",275,230);
font1.draw(batch,"Your points:"+points,348,250);
if(Gdx.input.isTouched()){
longClick+=1;
if(longClick==35){
gameOver=false;
points=0;
longClick=0;
heliR.y=300;
heliR.x=30;
}
}else{
if(TimeUtils.nanoTime()- click > 2000000){longClick=0;}
}
}
//starting game
if(justStart==true){
heliR.y=250;
heliR.x=330;
font2.draw(batch,"Touch the screen to start",230,230);
batch.draw(logo,logoR.x,logoR.y);
font1.draw(batch,"Developed by:Monzterr",5,15);
if(Gdx.input.isTouched()){
justStart=false;
heliR.y=300;
heliR.x=30;
}
}
batch.end();
//game physics
if(justStart==false&&gameOver==false){
//missile
if(TimeUtils.nanoTime()-lastMissile > 1000000000){spawnMissile();}
Iterator <Rectangle> iter=missiles.iterator();
while(iter.hasNext()){
Rectangle missile= iter.next();
missile.x-=velocity*Gdx.graphics.getDeltaTime();
if(missile.x<=-10){iter.remove();}
if(missile.overlaps(heliR)){
gameOver=true;
collision.play();
}
if(gameOver==true){
iter.remove();
}
}
//background
backGroundX= backGroundX-100*Gdx.graphics.getDeltaTime();
if(backGroundX<=0){
backGroundX=800;
}
//score
if(TimeUtils.nanoTime()-lastScore>2000000000){
points=points+1;
lastScore=TimeUtils.nanoTime();
}
//gravity
if(Gdx.input.isTouched()){
heliR.y+=5;
//heliLanding.play();
}else{
heliR.y-=5;
//heliLanding.pause();
}
}
//borders
if(heliR.y>=400){
heliR.y=250;
}
if(heliR.y<=56){
heliR.y=56;
gameOver=true;
mX=800;
collision.play();
}
}
#Override
public void dispose()
{
}
#Override
public void resize(int width, int height)
{
}
#Override
public void pause()
{
}
#Override
public void resume()
{
}
Sorry for messy code I just started learning programming last week.
You are checking if gameOver == true twice - one on the (almost) beginning of the render() method
//game over
if(gameOver==true){
heliR.y=250;
...
and second time under following condition
//game physics
if(justStart==false&&gameOver==false){
...
but you are removing iterator only in the second one
if(gameOver==true){
iter.remove();
}
fixing it should fix your problem. Consider also do you need two checks if gameOver is true (I believe you not - you can handle both situations in the first one)
You are changing gameOver to true in the middle of looping through all your enemies, and only removing them from within the loop, so only the enemies after the one that caused the game over will be removed. Replace iter.remove() with break (to jump out of the loop which is now unnecessary to finish). And then add a line after the loop:
if (gameOver) missiles.clear();
This removes everything from the array.
Say I have a splash screen. This screen is loaded only at the beginning of the game, and afterwards I don't use it.
Is it possible to dispose this screen on demand?
I tried to dispose it right after setting the screen after the splash, and also tried to call dispose() on the hide() method.
Both of the tries rendered in an exception.
How can I dispose this screen on demand? I have there pretty heavy textures, and wanted to free the memory as soon as possible.
Example:
// SplashScreen class
class SplashScreen implements Screen {
private boolean renderingEnabled = true;
private Object lock = new Object();
#Override
public void render(float delta) {
synchronized(lock) {
if (!renderingEnabled) {
return;
}
spriteBatch.begin();
// here render the animations
spriteBatch.end();
}
}
#Override
public void dispose() {
synchronized(lock) {
renderingEnabled = false;
// here come the disposing of SpriteBatch and TextureAtlas
atlas.dispose();
atlas = null;
spriteBatch.dispose();
spriteBatch = null;
}
}
}
// The usage
game.setScreen(splashScreen);
...
// now when the splash screen animation is finished, I am calling the following from the controller:
splashScreen.dispose();
game.setScreen(mainMenuScreen);
I get the following exception:
FATAL EXCEPTION: GLThread 398
java.lang.NullPointerException
at mypackage.SplashScreen.render(SplashScreen.java:85)
at com.badlogic.gdx.Game.render(Game.java:46)
at mypackage.Game.render(MyGame.java:33)
at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(AndroidGraphics.java:414)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1522)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)
And when I have the following dispose pattern (disposing after showing the mainMenuScreen)
// The usage
game.setScreen(splashScreen);
...
// now when the splash screen animation is finished, I am calling the following from the controller:
game.setScreen(mainMenuScreen);
splashScreen.dispose();
I get the same exception.
The exception is on spriteBatch.end() row inside the render method. The spriteBatch member turns to be null. Really confusing, since I have mutual exclusive lock on the render and the dispose methods.
What I figured out, is that LibGDX works in one thread.
What happens is the following. When the game.setScreen(mainMenuScreen) is called, and the program is in the middle of the render method of the splash screen, the thread is interrupted, and the code for setting the mainMenuScreen is executed (in the Game class), and then going back to continue the render method of the splash screen. Weird, right? After setting the new screen still to render the old screen?
Anyways, what I did is the following:
As part of the Game.setScreen(Screen screen) method, the Screen.hide() method is called on the old screen.
So what I did, I introduced a flag, hideCalled and set it to true in the hide() event inside the splash screen.
Inside the render method of the splash screen I check this flag at the beginning and at the end of the method. If the flag is true - I dispose the screen.
I was just thinking about AssetManager, maybe it would help you with this problem in a cleaner way.
Take a look here.
I see it loads assets asynchronously so maybe this problem that you described would not be happening again.
And just for some knowledge sharing, I changed screens with another approach:
I used actions attached to an image, and these actions are executed in the order they are added. First i created an action which loads the images, then, when this first action was finished, i added another action which switches the screen.
Here is my code:
#Override
public void show() {
stage.addActor(splashImage);
splashImage.addAction(Actions.sequence(Actions.alpha(0), Actions.run(new Runnable() {
#Override
public void run() {
Assets.load();
}
}), Actions.fadeIn(0.5f), Actions.delay(1), Actions.fadeOut(0.5f), Actions.run(new Runnable() {
#Override
public void run() {
Utils.changeGameScreen(new GameScreen());
// ((Game) Gdx.app.getApplicationListener()).setScreen(new
// GameScreen());
}
})));
}