I made a test game in unity that makes it so when I click on a button, it spawns a cylinder created from a factory class. I'm trying to make it so when I create the cylinder, its height shrinks over the next 20 seconds. Some methods I found are difficult to translate into what I'm doing. If you could lead me to the right direction, I'd very much appreciate it.
Here's my code for the cylinder class
public class Cylinder : Shape
{
public Cylinder()
{
GameObject cylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
cylinder.transform.position = new Vector3(3, 0, 0);
cylinder.transform.localScale = new Vector3(1.0f, Random.Range(1, 2)-1*Time.deltaTime, 1.0f);
cylinder.GetComponent<MeshRenderer>().material.color = Random.ColorHSV();
Destroy(cylinder, 30.0f);
}
}
This can be done with the Time.deltaTime and Vector3.Lerp in a coroutine function. Similar to Rotate GameObject over time and Move GameObject over time questions. Modified it a little bit to do just this.
bool isScaling = false;
IEnumerator scaleOverTime(Transform objectToScale, Vector3 toScale, float duration)
{
//Make sure there is only one instance of this function running
if (isScaling)
{
yield break; ///exit if this is still running
}
isScaling = true;
float counter = 0;
//Get the current scale of the object to be moved
Vector3 startScaleSize = objectToScale.localScale;
while (counter < duration)
{
counter += Time.deltaTime;
objectToScale.localScale = Vector3.Lerp(startScaleSize, toScale, counter / duration);
yield return null;
}
isScaling = false;
}
USAGE:
Will scale GameObject within 20 seconds:
StartCoroutine(scaleOverTime(cylinder.transform, new Vector3(0, 0, 90), 20f));
Check out Lerp. A general example of how to use it would be something like this:
float t = 0;
Update()
{
t += Time.deltaTime;
cylinder.localScale = new Vector3(1, Mathf.Lerp(2f, 1f, t/3f), 1); // shrink from 2 to 1 over 3 seconds;
}
You will create a new monobehaviour script and add it to your primitive. Then you wil use "Update" method of monobehaviour (or use coroutine) for change object over time.
Monobehaviour must be look like this:
public class ShrinkBehaviour : MonoBehaviour
{
bool isNeedToShrink;
Config currentConfig;
float startTime;
float totalDistance;
public void StartShrink(Config config)
{
startTime = Time.time;
currentConfig = config;
totalDistance = Vector3.Distance(currentConfig.startSize, currentConfig.destinationSize);
isNeedToShrink = true;
transform.localScale = config.startSize;
}
private void Update()
{
if (isNeedToShrink)
{
var nextSize = GetNextSize(currentConfig);
if (Vector3.Distance(nextSize, currentConfig.destinationSize) <= 0.05f)
{
isNeedToShrink = false;
return;
}
transform.localScale = nextSize;
}
}
Vector3 GetNextSize(Config config)
{
float timeCovered = (Time.time - startTime) / config.duration;
var result = Vector3.Lerp(config.startSize, config.destinationSize, timeCovered);
return result;
}
public struct Config
{
public float duration;
public Vector3 startSize;
public Vector3 destinationSize;
}
}
For using this, you must do next:
public Cylinder()
{
GameObject cylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
var shrink = cylinder.AddComponent<ShrinkBehaviour>();
shrink.StartShrink(new ShrinkBehaviour.Config() { startSize = Vector3.one * 10, destinationSize = Vector3.one * 1, duration = 20f });
cylinder.transform.position = new Vector3(3, 0, 0);
cylinder.GetComponent<MeshRenderer>().material.color = Random.ColorHSV();
Destroy(cylinder, 30.0f);
}
You must remember, monobehaviour-script must be in separate file, and must have name similar to monobehaviour-class name. For example, ShrinkBehaviour.cs;
Related
I'm doing the "Your First 2D Game" in Godot because I'm a beginner. I used C# as my script language.
I'm having a problem with GetNode("/root/Main/StartTimer") giving to me a System.InvalidCastException: Specified cast is not valid.
But, StartTimer is the Timer type. So, There's no way it could launch this exception.
I'm exactly at this page of the tutorial:
https://docs.godotengine.org/en/stable/getting_started/first_2d_game/05.the_main_game_scene.html
public void New_Game()
{
Score = 0;
var player = GetNode<Player>("/root/Main/Player");
var startPosition = GetNode<Position2D>("/root/Main/StartPosition");
player.Start(startPosition.Position);
GetNode<Timer>("/root/Main/StartTimer").Start();
}
Well, I don't know what to do, since I'm following the tutorial. I think it shouldn't happen because StartTimer is the type Timer, screenshot below:
These are all my scripts:
Main.cs script:
using Godot;
using System;
public class Main : Node
{
// Declare member variables here. Examples:
// private int a = 2;
// private string b = "text";
#pragma warning disable 649
[Export]
public PackedScene MobScene;
#pragma warning restore 649
public int Score;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
GD.Randomize();
New_Game();
}
// // Called every frame. 'delta' is the elapsed time since the previous frame.
// public override void _Process(float delta)
// {
//
// }
public void Game_Over()
{
GetNode<Timer>("MobTimer").Stop();
GetNode<Timer>("ScoreTimer").Stop();
}
public void New_Game()
{
Score = 0;
var player = GetNode<Player>("/root/Main/Player");
var startPosition = GetNode<Position2D>("/root/Main/StartPosition");
player.Start(startPosition.Position);
GetNode<Timer>("/root/Main/StartTimer").Start();
//Timer StartTimer = GetNode<Timer>("/root/Main/StartTimer");
}
public void OnScoreTimerTimeout()
{
Score++;
}
public void OnStartTimerTimeout()
{
GetNode<Timer>("MobTimer").Start();
GetNode<Timer>("ScoreTimer").Start();
}
public void OnMobTimerTimeout()
{
//Create a new instance of the Mob Scene
var mob = (Mob)MobScene.Instance();
//Choose a random Location on Path2D
var mobSpawnLocation = GetNode<PathFollow2D>("MobPath/MobSpawnLocation");
mobSpawnLocation.Offset = GD.Randi();
//Set the mon's direction perpendicular to the path direction.
float direction = mobSpawnLocation.Rotation + Mathf.Pi / 2;
//Set the mob's position to a random location.
mob.Position = mobSpawnLocation.Position;
//Add some randomness to the direction
direction += (float)GD.RandRange(-Mathf.Pi / 4, Mathf.Pi / 4);
mob.Rotation = direction;
// Choose the velocity.
var velocity = new Vector2((float)GD.RandRange(150.0, 250.0), 0);
mob.LinearVelocity = velocity.Rotated(direction);
// Spawn the mob by adding it to the Main scene.
AddChild(mob);
}
}
Mobs.cs script:
using Godot;
using System;
public class Mob : RigidBody2D
{
// Declare member variables here. Examples:
// private int a = 2;
// private string b = "text";
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
var animSprite = GetNode<AnimatedSprite>("AnimatedSprite");
animSprite.Playing = true;
string[] mobTypes = animSprite.Frames.GetAnimationNames();
animSprite.Animation = mobTypes[GD.Randi() % mobTypes.Length];
}
// // Called every frame. 'delta' is the elapsed time since the previous
frame.
// public override void _Process(float delta)
// {
//
// }
public void OnVisibilityNotifier2DScreenExited()
{
QueueFree();
}
}
Player.cs script:
using Godot;
using System;
public class Player : Area2D
{
// Declare member variables here. Examples:
// private int a = 2;
// private string b = "text";
//How fast the player will move (pixel/sec).
[Export]
public int Speed = 400;
[Signal]
public delegate void Hit();
// Size of the game window.
public Vector2 ScreenSize;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
ScreenSize = GetViewportRect().Size;
Hide(); //Player is hidden when the game starts
}
// Called every frame. 'delta' is the elapsed time since the previous
frame.
public override void _Process(float delta)
{
var velocity = Vector2.Zero; //Tha Player's movement vector
if (Input.IsActionPressed("move_right"))
{
velocity.x += 1;
}
if (Input.IsActionPressed("move_left"))
{
velocity.x -= 1;
}
if (Input.IsActionPressed("move_down"))
{
velocity.y += 1;
}
if (Input.IsActionPressed("move_up"))
{
velocity.y -= 1;
}
var animatedSprite = GetNode<AnimatedSprite>("AnimatedSprite");
if (velocity.Length() > 0)
{
velocity = velocity.Normalized() * Speed;
animatedSprite.Play();
}
else
{
animatedSprite.Stop();
}
Position += velocity * delta;
Position = new Vector2(
x: Mathf.Clamp(Position.x, 0, ScreenSize.x),
y: Mathf.Clamp(Position.y, 0, ScreenSize.y)
);
if (velocity.x != 0)
{
animatedSprite.Animation = "walk";
animatedSprite.FlipV = false;
animatedSprite.FlipH = velocity.x < 0; //Here I'm doing a boolean
test
}
else if (velocity.y != 0)
{
animatedSprite.Animation = "up";
animatedSprite.FlipV = velocity.y > 0; //Here I'm doing a boolean
test
}
}
public void On_Player_Body_Entered(PhysicsBody2D body)
{
Hide(); //Player disappears after being hit.
EmitSignal(nameof(Hit));
//Must be deferred as we can't change physics properties on a physics
callback.
GetNode<CollisionShape2D>("CollisionShape2D").SetDeferred("disabled",
true);
}
//Reset the player when starting the game
public void Start(Vector2 pos)
{
Position = pos;
Show();
GetNode<CollisionShape2D>("CollisionShape2D").Disabled = false;
}
}
If you can help me, please.. I'd be very glad and thankful if you could! Thank you!
The reason your game crashes is because of the main.cs script that is attached to all timer nodes.
Since the main.cs script extends the Node object all your timers are becoming Node objects instead of Timer objects. And because Node objects do not have a Start() function your game crashes.
The simple solution to this is to detach the main script from all nodes but the main node.
As Bugfish pointed out, Godot must not attach a script to a node when you connect a signal. Especially not a script from another node. After you deleted your main script from the timers, I recommend to go through the process of signal connection again just to figure out what went wrong the first time.
I have a raycast going upwards from an object which when the player comes in contact with the ray the object changes color. That works but I want to do it so when you touch the ray a second time, the object gets destroyed and I have no idea how to do that. I'm using Unity 2d.
Code: `using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DestroyEnemy : MonoBehaviour //Enemy 3
{
[SerializeField] Transform Enemy3WayPoint;
private Renderer rend;
private Color colorToTurnTo = Color.blue;
void Start()
{
rend = GetComponent<Renderer>();
rend.enabled = true;
Physics2D.queriesStartInColliders = false;
}
private void Update()
{
RaycastHit2D hitInfo = Physics2D.Raycast(transform.position, Vector3.up, 5);
if (hitInfo.collider.gameObject.tag == "Player")
{
rend.material.color = colorToTurnTo;
Debug.DrawLine(transform.position, hitInfo.point, Color.white);
}`
There may be a bracket or two I forgot to include, it does work when I test it
I think the simplest solution is to use a variable to keep track of the number of times the ray has been hit by the player.
As for destroying the enemy, you can use the destroy function.
So, something like this:
int hitCount = 0; //add a class variable
void Update(){
RaycastHit2D hitInfo = Physics2D.Raycast(transform.position, Vector3.up, 5);
if (hitInfo.collider.gameObject.tag == "Player")
{
hitCount++;
}
if(hitCount == 1)
{
rend.material.color = colorToTurnTo;
Debug.DrawLine(transform.position, hitInfo.point, Color.white);
}
else if(hitCount >= 2)
{
Destroy(gameObject); //this will destroy the gameObject that the component is attached to
}
}
EDIT: It seems the OP's main problem was adding a delay to the events. Here is some updated code that addresses that problem:
bool waitingForFirstHit = true;
bool waitingForSecondHit = false;
float timeDelay = 1.5f;
void Update(){
RaycastHit2D hitInfo = Physics2D.Raycast(transform.position, Vector3.up, 5);
if (hitInfo.collider.gameObject.tag == "Player" )
{
if (waitingForFirstHit) {
ChangeColor();
waitingForFirstHit = false;
waitingForSecondHit = true;
}
else if(waitingForSecondHit && timeDelay < 0)
{
DestroyEnemy ();
}
}
if(waitingForSecondHit)
{
timeDelay -= Time.deltaTime;
}
}
void ChangeColor()
{
rend.material.color = colorToTurnTo;
Debug.DrawLine(transform.position, hitInfo.point, Color.white);
}
void DestroyEnemy()
{
Destroy(gameObject);
}
Here is a tutorial on using the Destroy function:
https://unity3d.com/learn/tutorials/topics/scripting/destroy
And here is a link to the docs:
https://docs.unity3d.com/ScriptReference/Object.Destroy.html
Cheers.
Hello I am developing a game on my spare time with AIDE and libGDX. Though AIDE has some missing methods of the libGDX API and I had to create some workarounds to compensate for the missing methods.
So my problem is that with every instance of a collision the app becomes more and more laggy. No new textures are being drawn and non go away. Just a poor implementation that is meant to push you out of said collision tile. It runs fine until you have a few collisions. My thought is that it creates a new variable with every collision and stores it into memory causing a leak. But I can't really tell if that is the case. Oh I'd like to add that I don't have access to a computer, just my phone. Here is my movement class
move.java
public class move
{
float posX;
float posY;
float touchedOnScreenX;
float touchedOnScreenY;
float centerOfScreenX;
float centerOfScreenY;
float posXSetter;
float posYSetter;
float Speed = 150;
float mapBoundsWidth;
float mapBoundsHeight;
boolean upperBounds;
boolean lowerBounds;
boolean rightBounds;
boolean leftBounds;
boolean tileCollition;
public move() {
}
public void renderMove(float delta) {
if(Gdx.input.isTouched()) {
screenAndTouchInfo();
checkBoundsBoolean();
checkForCollision();
}
}
//slows game down
private void checkForCollision()
{
if (upperBounds == false)
{
if (lowerBounds == false)
{
if (rightBounds == false)
{
if (leftBounds == false)
{
if (tileCollition == false)
{
movement();
}
else
{
collitionSide();
}
}
else
{
posX++;
}
}
else
{
posX--;
}
}
else
{
posY++;
}
}
else
{
posY --;
}
}
private void movement()
{
posYSetter = posY;
posXSetter = posX;
if (touchedOnScreenX < centerOfScreenX)
{
posX -= Gdx.graphics.getDeltaTime() * Speed;
}
else
{
posX += Gdx.graphics.getDeltaTime() * Speed;
}
if (touchedOnScreenY < centerOfScreenY)
{
posY -= Gdx.graphics.getDeltaTime() * Speed;
}
else
{
posY += Gdx.graphics.getDeltaTime() * Speed;
}
if (touchedOnScreenY < centerOfScreenY + 64 && touchedOnScreenY > centerOfScreenY - 64)
{
posY = posYSetter;
}
if (touchedOnScreenX < centerOfScreenX + 64 && touchedOnScreenX > centerOfScreenX - 64)
{
posX = posXSetter;
}
}
//buggy and slows game down. Can push you into tile if input is the opposite of the side
public void collitionSide() {
if (tileCollition == true){
if (touchedOnScreenX < centerOfScreenX)
{
posX = posX +10;
}
else
{
posX = posX - 10;
}
if (touchedOnScreenY < centerOfScreenY)
{
posY = posY +10;
}
else
{
posY = posY -10;
}
}
}
private void screenAndTouchInfo()
{
touchedOnScreenX = Gdx.input.getX();
touchedOnScreenY = (Gdx.graphics.getHeight() - Gdx.input.getY());
centerOfScreenX = Gdx.graphics.getWidth() / 2;
centerOfScreenY = Gdx.graphics.getHeight() / 2;
}
//slows game down
private void checkBoundsBoolean()
{
if (posX > mapBoundsWidth)
{
rightBounds = true;
}
else {
rightBounds = false;
}
if (posY > mapBoundsHeight)
{
upperBounds = true;
}
else {
upperBounds = false;
}
if (posX < mapBoundsWidth - mapBoundsWidth)
{
leftBounds = true;
}
else {
leftBounds = false;
}
if (posY < mapBoundsHeight - mapBoundsHeight)
{
lowerBounds = true;
}
else {
lowerBounds = false;
}
}
public void setTileCollision(boolean tileCollision) {
this.tileCollition = tileCollision;
}
public float getPosX() {
return posX;
}
public float getPosY() {
return posY;
}
public float getTouchedOnScreenX() {
return touchedOnScreenX;
}
public float getTouchedOnScreenY() {
return touchedOnScreenY;
}
public float getCenterOfScreenX() {
return centerOfScreenX;
}
public float getCenterOfScreenY() {
return centerOfScreenY;
}
public void setMapboundsWidth(float width) {
this.mapBoundsWidth = width;
}
public void setMapboundsHeight(float height) {
this.mapBoundsHeight = height;
}
}
I know that is a lot of code to comb through and I am sorry if it isn't always clear what is going on. I refactored it to where it would be a little easier to understand. Oh if anyone could tell me why AIDE is missing some methods of libGDX that would be nice too.The most notable one would be Cell.setTile(). That I know is in libGDX's API and can be found in their documentation. But when I implement it it throws a unknown method of class Cell error. I have researched on how to use the method as well with no avail. Had to create int[][] map and a for loop to draw map with another Texture[]. It works. Lol. Thank you to whomever even took the time to look at my long winded double question. Hopefully someone can tell me why this lag is created from said collisions.
I recommend moving your collision code into a separate thread. This should improve performance significantly:
Executor executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
#Override
public void run() {
// Physics loop goes here
}
});
Make sure to shutdown the executor when disposing your screen.
I have an error regarding Null Pointer Exception and I can't find the exact location of the error in my program. I have searched for probable solutions online but I find none of them helpful. I know what Null Pointer Exception is but I can't pinpoint what went wrong in my code. Any help will be appreciated, thanks.
Here's my code:
LevelOneScreen.java
public class LevelOneScreen implements Screen {
private final ThumbChase app;
WalkAnimate walkAnimate;
private Stage stage;
private Image levelOneImage;
private Image holdStartImage;
public Image walkRightImage;
public Image walkLeftImage;
public float deltaTime = Gdx.graphics.getDeltaTime();
public LevelOneScreen(final ThumbChase app){
this.app = app;
this.stage = new Stage(new StretchViewport(app.screenWidth,app.screenHeight , app.camera));
}
#Override
public void show() {
Gdx.input.setInputProcessor(stage);
walkAnimate = new WalkAnimate();
levelOneBackground();
holdStart();
ninjaWalk(); ==>ERROR1:LevelOneScreen.java:54
}
public void holdStart(){
Texture holdStartTexture = new Texture("HoldStart.png");
holdStartImage = new Image(holdStartTexture);
float holdStartImageW = holdStartImage.getWidth();
float holdStartImageH = holdStartImage.getHeight();
float holdStartImgWidth = app.screenWidth*0.8f;
float holdStartImgHeight = holdStartImgWidth *(holdStartImageH/holdStartImageW);
holdStartImage.isTouchable();
holdStartImage.setSize(holdStartImgWidth,holdStartImgHeight);
holdStartImage.setPosition(stage.getWidth()/2-holdStartImgWidth/2,stage.getHeight()/2-holdStartImgHeight/2);
stage.addActor(holdStartImage);
holdStartImage.addListener(new ActorGestureListener(){
public void touchDown (InputEvent event, float x, float y, int pointer, int button){
holdStartImage.setVisible(false);
};
});
}
public void levelOneBackground(){
Texture levelOneTexture = new Texture("BGBlue Resize.png");
levelOneImage = new Image(levelOneTexture);
levelOneImage.setSize(app.screenWidth,app.screenHeight);
levelOneImage.setPosition(0,0);
stage.addActor(levelOneImage);
levelOneImage.addListener(new ActorGestureListener(){
public void touchDown (InputEvent event, float x, float y, int pointer, int button){
holdStartImage.setVisible(false);
};
});
}
public void ninjaWalk(){
ERROR2==> TextureRegion ninjaWalkRight = new TextureRegion(walkAnimate.getCurrentFrameRight());
TextureRegion ninjaWalkLeft = new TextureRegion(walkAnimate.getCurrentFrameLeft());
walkRightImage = new Image(ninjaWalkRight);
walkLeftImage = new Image(ninjaWalkLeft);
float walkImageW = walkRightImage.getWidth();
float walkImageH = walkRightImage.getHeight();
float walkImageWidth = app.screenWidth*0.15f;
float walkImageHeight = walkImageWidth*(walkImageH/walkImageW);
walkLeftImage.isTouchable();
walkRightImage.isTouchable();
walkRightImage.setSize(walkImageWidth,walkImageHeight);
walkLeftImage.setSize(walkImageWidth,walkImageHeight);
walkRightImage.setPosition(stage.getWidth()/2-walkImageWidth/2,0);
walkLeftImage.setPosition(stage.getWidth()/2-walkImageWidth/2,0);
walkLeftImage.addAction(moveBy(3f,3f,3f));
stage.addActor(walkLeftImage);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
walkAnimate.update(deltaTime);
update(delta);
}
public void update(float delta){
stage.act(delta);
stage.draw();
app.batch.begin();
app.batch.end();
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
stage.dispose();
}
}
WalkAnimate.java
public class WalkAnimate {
public ThumbChase app;
public Stage stage;
private Animation walkAnimationRight;
private Animation walkAnimationLeft;
private Texture walkSheetRight;
private Texture walkSheetLeft;
private TextureRegion[] walkFramesRight;
private TextureRegion[] walkFramesLeft;
private TextureRegion currentFrameRight;
private TextureRegion currentFrameLeft;
private float stateTime;
private Rectangle bound; //used for positioning and collision detection
private static final int FRAME_COLS_WALK = 3;
private static final int FRAME_ROWS_WALK= 2;
private float screenWidth = Gdx.graphics.getWidth();
private float screenHeight = Gdx.graphics.getHeight();
public float currentFrameWidth = (float)(screenHeight*0.15);
public float currentFrameHeight = (float)(screenHeight*0.15);
public float walkSheetWidth;
public float walkSheetHeight;
public WalkAnimate () {
walkSheetRight = new Texture("ninjaWalkRight.png");
walkSheetWidth = walkSheetRight.getWidth();
walkSheetHeight = walkSheetRight.getWidth();
TextureRegion[][] tmp = TextureRegion.split(walkSheetRight, (int) walkSheetRight.getWidth() / FRAME_COLS_WALK, (int) walkSheetRight.getHeight() / FRAME_ROWS_WALK);
walkFramesRight = new TextureRegion[FRAME_COLS_WALK * FRAME_ROWS_WALK];
int index = 0 ;
for (int i = 0; i < FRAME_ROWS_WALK; i++) {
for (int j = 0; j < FRAME_COLS_WALK; j++) {
walkFramesRight[index++] = tmp[i][j];
}
}
walkAnimationRight = new Animation(0.044f, walkFramesRight);
stateTime = 0f;
walkSheetLeft = new Texture("ninjaWalkLeft.png");
walkSheetWidth = walkSheetLeft.getWidth();
walkSheetHeight = walkSheetLeft.getWidth();
TextureRegion[][] tmp1 = TextureRegion.split(walkSheetLeft, (int) walkSheetRight.getWidth() / FRAME_COLS_WALK, (int)walkSheetLeft.getHeight() / FRAME_ROWS_WALK);
walkFramesLeft = new TextureRegion[FRAME_COLS_WALK * FRAME_ROWS_WALK];
int index1 = 0;
for (int i = 0; i < FRAME_ROWS_WALK; i++) {
for (int j = 0; j < FRAME_COLS_WALK; j++) {
walkFramesLeft[index1++] = tmp1 [i][j];
}
}
walkAnimationLeft = new Animation(0.044f, walkFramesLeft);
stateTime = 0f;
}
public Rectangle getBound(){
return bound;
}
public void update(float delta){
stateTime += delta;
currentFrameRight = walkAnimationRight.getKeyFrame(stateTime, true);
currentFrameLeft = walkAnimationLeft.getKeyFrame(stateTime, true);
}
public TextureRegion getCurrentFrameRight(){
return currentFrameRight;
}
public TextureRegion getCurrentFrameLeft(){
return currentFrameLeft;
}
}
And here's the error:
> java.lang.NullPointerException
> at
> com.badlogic.gdx.graphics.g2d.TextureRegion.setRegion(TextureRegion.java:112)
> at
> com.badlogic.gdx.graphics.g2d.TextureRegion.<init>(TextureRegion.java:63)
> at
> com.jpfalmazan.thumbchaseninja.GameScreens.LevelOneScreen.show(LevelOneScreen.java:54)
> at com.badlogic.gdx.Game.setScreen(Game.java:61)
> at
> com.jpfalmazan.thumbchaseninja.GameScreens.MenuScreen$1.clicked(MenuScreen.java:82)
> at
> com.badlogic.gdx.scenes.scene2d.utils.ClickListener.touchUp(ClickListener.java:89)
> at
> com.badlogic.gdx.scenes.scene2d.InputListener.handle(InputListener.java:58)
> at com.badlogic.gdx.scenes.scene2d.Stage.touchUp(Stage.java:353)
> at
> com.badlogic.gdx.backends.android.AndroidInput.processEvents(AndroidInput.java:379)
> at
> com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(AndroidGraphics.java:457)
> at
> android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1516)
> at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)
you can find the exact line in logcat logs, you can see the activity name as well as the line of code and by clicking on it you will be redirected to the individual Activity on same line..
Hope this will help you.
One of your textures is either named wrong, or you are attempting to access it before it has been loaded.
You can tell by this exception;
com.badlogic.gdx.graphics.g2d.TextureRegion.setRegion(TextureRegion.java:112)
This mean that the texture region cannot map the texture identifier to a valid texture in your program, so either ninjaWalkRight or ninjaWalkLeft does not exist or is not loaded.
If you are using texture packer then ensure your files are called ninjaWalkRight and ninjaWalkLeft.
Also use the AssetManager to ensure these files are loaded before trying to access them as that may be an issue also.
Looks like you don't call walkAnimate.update(dt) before calling walkAnimate.getCurrentFrameRight() the first time, so walkAnimate.getCurrentFrameRight() returns null.
Moreover, in ninjaWalk() you create two actors (walkRightImage and walkLeftImage), only add one to the stage and never update the texture of it. You should rework your concept: Create one actor at startup, store it in a field and change the texture of it in your render/update method.
I have a MvxDialogViewController and I'm trying to use the progress indicator shown in the Xamarin example by adding bindable properties.
I can get the indicator to appear when I set Visble to true programatically but not when I bind to a vm property.
Here is the view code:
var bindings = this.CreateInlineBindingTarget<LoginViewModel>();
Root = new RootElement("Login")
{
new Section("Login Credentials")
{
new EntryElement("Username", "Enter user name").Bind(bindings, vm => vm.UserName),
new EntryElement("Password", "Enter password", "", true).Bind(bindings, vm => vm.Password)
}
};
_bindableProgress = new BindableProgress(UIScreen.MainScreen.Bounds).Bind(bindings, b => b.Visible, vm => vm.IsBusy);
_bindableProgress.Title = "Logging in...";
View.Add(_bindableProgress);
I also tried to bind like this:
var set = this.CreateBindingSet<LoginView, LoginViewModel>();
set.Bind(_bindableProgress).For(b => b.Title).To(vm => vm.ProgressTitle);
set.Bind(_bindableProgress).For(b => b.Visible).To(vm => vm.IsBusy);
set.Apply();
But neither way worked.
Here is by BindableProgress class:
public class BindableProgress : UIView
{
private UIActivityIndicatorView _activitySpinner;
private UILabel _loadingLabel;
public string Title { get; set; }
private bool _visible;
public bool Visible
{
get { return _visible; }
set
{
_visible = value;
if (_visible)
{
Show();
}
else
{
Hide();
}
}
}
public BindableProgress(RectangleF frame) : base(frame)
{
// configurable bits
BackgroundColor = UIColor.Black;
Alpha = 0;
AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;
float labelHeight = 22;
float labelWidth = Frame.Width - 20;
// derive the center x and y
float centerX = Frame.Width/2;
float centerY = Frame.Height/2;
// create the activity spinner, center it horizontally and put it 5 points above center x
_activitySpinner = new UIActivityIndicatorView(UIActivityIndicatorViewStyle.WhiteLarge);
_activitySpinner.Frame = new RectangleF(
centerX - (_activitySpinner.Frame.Width / 2),
centerY - _activitySpinner.Frame.Height - 20,
_activitySpinner.Frame.Width,
_activitySpinner.Frame.Height);
_activitySpinner.AutoresizingMask = UIViewAutoresizing.FlexibleMargins;
AddSubview(_activitySpinner);
// create and configure the label
_loadingLabel = new UILabel(new RectangleF(
centerX - (labelWidth/2),
centerY + 20,
labelWidth,
labelHeight
));
_loadingLabel.BackgroundColor = UIColor.Clear;
_loadingLabel.TextColor = UIColor.White;
_loadingLabel.TextAlignment = UITextAlignment.Center;
_loadingLabel.AutoresizingMask = UIViewAutoresizing.FlexibleMargins;
AddSubview(_loadingLabel);
}
private void Show()
{
_loadingLabel.Text = Title;
Alpha = 0.75f;
_activitySpinner.StartAnimating();
}
/// <summary>
/// Fades out the control and then removes it from the super view
/// </summary>
private void Hide()
{
_activitySpinner.StopAnimating();
Animate(
0.5, // duration
() => { Alpha = 0; },
() => { RemoveFromSuperview(); }
);
}
}
Any ideas?
UPDATE
My vm property looks like this
private bool _isBusy;
public bool IsBusy
{
get { return _isBusy; }
set { _isBusy = value; RaisePropertyChanged(() => IsBusy); }
}
It works fine in Android so I'm guessing the problem in not with that.
IsBusy is probably false at binding time. So _visible is set to false and Hide() is called. Now the view is removed from the superview and you can't show it anymore, because Show() doesn't add it to the superview again. Try to omit the RemoveFromSuperview();. Or modify the Visible property like this:
public bool Visible
{
get { return _visible; }
set
{
if(_visible == value)
return;
_visible = value;
if (_visible)
{
Show();
}
else
{
Hide();
}
}
}