How to stop the move Modifier in AndEngine? - andengine

Here's the method I used to move a sprite in X-axis
public void moveX(float constanttime,float fromX,int toX,final Sprite s){
MoveXModifier mod2=new MoveXModifier(constanttime, fromX, toX);
s.registerEntityModifier(mod2);
}
I'm calling this method like this when I want to start moving the sprite.
moveX(5, car1.getX(), -100, car1);
(car1 is the sprite I want to move)
I want to stop moving this sprite when the user touches the sprite(car1).
Can someone help me with this?

Actually you can pause entity modifiers (and all updates regarding specific entities individually). The following code allows you to pause an entity's updates based on a boolean value manipulated via touch events (not registered to the scene in the snippet). The following code snippet will cause modifiers on the entity to pause until isActionUp() is called. You can effectively pause entity updates (modifiers) by overriding the onManagedUpdate() method of an entity and passing a value of 0, which tells the entity 0 seconds have passed and to not update the entity modifiers.
boolean isTouched = false;
final Rectangle rectangle = new Rectangle(0, 0, 0, 0, mResourceManager.getEngine().getVertexBufferObjectManager()){
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
float pTouchAreaLocalX, float pTouchAreaLocalY) {
if(pSceneTouchEvent.isActionDown()){
isTouched = true;
}
if(pSceneTouchEvent.isActionUp()){
isTouched = false;
}
return super
.onAreaTouched(pSceneTouchEvent, pTouchAreaLocalX, pTouchAreaLocalY);
}
#Override
protected void onManagedUpdate(float pSecondsElapsed) {
if(isTouched){
super.onManagedUpdate(0);
} else {
super.onManagedUpdate(pSecondsElapsed);
}
}
};

Related

I want to make it so when I click on the enemy, an ammo drop appears on the screen

Here is my code piece of code (I already have it so that when you click a ghost the ammo spawns, I just didn't include that because it was in a procedure.) My problem is with the RNG spawning of the ammo; it works fine at first and then after like 20 seconds it just does not spawn at all.
private void ammoSpawn()
{
ammoSpawner = rng.Next(1, 101);
if (ammoSpawner > 50)
{
ammoTimer.Activate();
if (ammoTimer.IsActive())
{
ammoRec.X = rng.Next(100, 1720);
ammoRec.Y = rng.Next(100, 700);
if (ammoTimer.IsFinished())
{
ammoRec.X = -100;
ammoRec.Y = -100;
ammoTimer.ResetTimer(true);
}
}
}
}
Any help is appreciated
I'm guessing that you're reusing the same ammo object, and that the variables such as ammoSpawner and ammoTimer are public variables in game1.
I would recommend creating a seperate class for the ammo object. So all related code can remain in the ammo object, and that also makes it easier to create multiple items. (In case you're going to expand on that in the future)
An example of a create method in the Ammo Class:
int spawner = 0;
int timer = 0;
Texture2D ammoSprite = new Texture2D;
Rectangle rec = new Rectangle(x, y, width, height);
public void Ammo(Texture2D ammoSprite, _spawner, _timer) //this should be the constructor that creates the class
{
spawner = _spawner;
timer = _timer;
rec.X = rng.Next(100, 1720);
rec.Y = rng.Next(100, 700);
}
public void Update()
{
//function where you put your update logic for the ammo object
}
public void Draw(Spritebatch spriteBatch)
{
//function where you put your draw logic for the ammo object
spriteBatch.Draw(ammoSprite, rect, Color.White);
}
then in the place where you'll use the ammo Class:
public Ammo ammo = null; //declared as a field on top of the page
private void ammoSpawn()
{
Ammo ammo = new Ammo(); //creating an Ammo object, should be inside
}
public void Update()
{
ammo.Update();
}
public void Draw()
{
SpriteBatch spriteBatch = new SpriteBatch();
ammo.Draw(spriteBatch);
}
Creating classes for objects are a core concept in C# to be able to reuse them. This also allows you to create multiple items/enemies that behave differently, but still keep the basic functions. I'd certainely recommend to learn about classes.

How to add collision physics in Unity Mapbox World Scale?

In World Scale AR, I want to move to an object I placed using SpawnOnMap. When I touch that object, I want that object to be erased. I made the Player have a script called PlayerController. I made a tag for the object so that when it touches, it should destroy or set it active. When I walk towards the object, nothing happens. I've tried OnTriggerEnter and OnCollisionEnter already. Is there some kind of method I'm missing that Mapbox provides?
public class PelletCollector : MonoBehaviour
{
public int count = 0;
// Start is called before the first frame update
void Start()
{
}
private void OnCollisionEnter(Collision other)
{
if (other.gameObject.tag == "Pellet")
{
count++;
Debug.Log("Collected Pellets: " + count);
other.gameObject.SetActive(false);
//Destroy(other.gameObject);
}
}
}

Unity Jumping Issue - Character won't jump if it walks to the platform

(This is a 2D project)
I have a jumping issue where if my character WALKS into an X platform, she won't jump, but when she JUMPS ONTO the X platform, she can perform a jump.
For the platforms I am currently using 2 Box Collider 2Ds (one with "is trigger" checked)
For the character I am currently using 2 Box Collider 2Ds (one with "is trigger" checked) and Rigidbody 2D.
Below is the code for jumping and grounded I am currently trying to use.
{
public float Speed;
public float Jump;
bool grounded = false;
void Start()
{
}
void Update()
{
if (Input.GetKeyDown(KeyCode.UpArrow))
{
if (grounded)
{
GetComponent<Rigidbody2D>().velocity = new Vector2(GetComponent<Rigidbody2D>().velocity.x, Jump);
}
}
}
void OnTriggerEnter2D()
{
grounded = true;
}
void OnTriggerExit2D()
{
grounded = false;
}
}
Issue arises on the same part of every platform. (Each square represents a single platform sprite and they have all the same exact characteristics, since I copy pasted each one of them). Please check the photo on this link: https://imgur.com/a/vTmHw
It happens because your squares have seperate colliders. Imagine this:
There are two blocks : A and B. You are standing on block A. Now you try to walk on block B. As soon as your Rigidbody2D collider touches block B, your character gets an event OnTriggerEnter2D(...). Now you claim, that you are grounded.
However, at this moment you are still colliding with block A. As soon as your Rigidbody2D no longer collides with block A, your character receives OnTriggerExit2D(...). Now you claim, that you are no longer grounded. But in fact, you are still colliding with block B.
Solution
Instead of having bool variable for checking if grounded, you could have byte type variable, called collisionsCounter:
Once you enter a trigger - increase the counter.
Once you exit a trigger - decrease the counter.
Do some checking to make sure you are actually above the collider!
Now, once you need to check if your character is grounded, you can just use
if (collisionsCounter > 0)
{
// I am grounded, allow me to jump
}
EDIT
Actually, after investingating question further, I've realized that you have totally unnecessary colliders (I'm talking about the trigger ones). Remove those. Now you have only one collider per object. But to get the calls for collision, you need to change:
OnTriggerEnter2D(...) to OnCollisionEnter2D(Collision2D)
OnTriggerExit2D(...) to OnCollisionExit2D(Collision2D)
Final code
[RequireComponent(typeof(Rigidbody2D))]
public sealed class Character : MonoBehaviour
{
// A constant with tag name to prevent typos in code
private const string TagName_Platform = "Platform";
public float Speed;
public float Jump;
private Rigidbody2D myRigidbody;
private byte platformCollisions;
// Check if the player can jump
private bool CanJump
{
get { return platformCollisions > 0; }
}
// Called once the script is started
private void Start()
{
myRigidbody = GetComponent<Rigidbody2D>();
platformCollisions = 0;
}
// Called every frame
private void Update()
{
// // // // // // // // // // // // // //
// Need to check for horizontal movement
// // // // // // // // // // // // // //
// Trying to jump
if (Input.GetKeyDown(KeyDode.UpArrow) && CanJump == true)
Jump();
}
// Called once Rigidbody2D starts colliding with something
private void OnCollisionEnter2D(Collision2D collision)
{
if(collision.collider.tag == TagName_Platform)
platformCollisions++;
}
// Called once Rigidbody2D finishes colliding with something
private void OnCollisionExit2D(Collision2D collision)
{
if(collision.collider.tag == TagName_Platform)
platformCollisions--;
}
// Makes Character jump
private void Jump()
{
Vector2 velocity = myRigidbody.velocity;
velocity.y = Jump;
myRigidbody.velocity = velocity;
}
}
Here can be minor typos as all the code was typed inside Notepad...
I think there are a couple of issues here.
Firstly, using Triggers to check this type of collision is probably not the best way forward. I would suggested not using triggers, and instead using OnCollisionEnter2D(). Triggers just detect if the collision space of two objects has overlapped each other, whereas normal collisions collide against each otehr as if they were two solid objects. Seen as though you are detecting to see if you have landed on the floor, you don't want to fall through the floor like Triggers behave.
Second, I would suggest using AddForce instead of GetComponent<Rigidbody2D>().velocity.
Your final script could look like something like this:
public class PlayerController : MonoBehaviour
{
public float jumpForce = 10.0f;
public bool isGrounded;
Rigidbody2D rb;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void OnCollisionEnter2D(Collision2D other)
{
// If we have collided with the platform
if (other.gameObject.tag == "YourPlatformTag")
{
// Then we must be on the ground
isGrounded = true;
}
}
void Update()
{
// If we press space and we are on the ground
if(Input.GetKeyDown(KeyCode.Space) && isGrounded)
{
// Add some force to our Rigidbody
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
// We have jumped, we are no longer on the ground
isGrounded = false;
}
}
}

Coroutine not starting

I'm using a lightning GameObject prefab to have a visual effect when i'm firing my weapon. When I fire, I enable that lightning object and I have a generic component that deactivates it after a certain delay.
The problem is that the "should wait" log is never reached, and instead of waiting the set delay, it waits much longer and doesn't actually deactivate the GameObject.
Here's the code for the DeactivateAfter component
public class DestroyAfter : MonoBehaviour {
[SerializeField]
private float delay;
private bool firstRun = true;
void OnEnable () {
if (firstRun == false) {
StartCoroutine(DestroyMethod());
}
firstRun = false;
}
public IEnumerator DestroyMethod() {
Debug.LogFormat("Should wait; Time: {0}", Time.time);
yield return new WaitForSeconds(delay);
Debug.LogFormat("Should deactivate; Time: {0}", Time.time);
gameObject.SetActive(false);
}
}
The condition never be true, you need to set firstRun condition to true first.
private bool firstRun = **true**;
void OnEnable () {
if (firstRun == **true**) {
StartCoroutine(DestroyMethod());
}
firstRun = false;
}
And i ever like to set flag first and later do what you want:
private bool firstRun = **true**;
void OnEnable () {
if (firstRun == **true**) {
firstRun = false;
StartCoroutine(DestroyMethod());
}
}
I think you should use particle system for your weapon fire. Anyway I think your code is not working because you are deactivating the game object instead of deactivating the component. Activate and deactivate your component using something like this :
gameObject.GetComponent<YourComponent>().enabled = false;
First Solution - Instantiate and Destroy with delay
If I understood you correctly the lightning GameObject is already a prefab you instantiate when firing and you want to destroy it after a delay.
So instead of a Coroutine solution and enabling or disabling the Object, this could be way simpler done using instantiate and destroy after as your script is actually called:
GameObject obj = GameObject.Instantiate(yourPrefab, position, rotation);
GameObject.Destroy(obj, delay);
This function can be called from anywhere as long as you have yourGameObject provided to the calling class. So you don't even need an own class for this.
The second float parameter is a delay in seconds (see API)
For example you could have a shooting class like:
public class Shooting : MonoBehavior
{
[SerializeField]
private GameObject lightningPrefab;
[SerializeField]
private float delay;
public void OnShooting(Vector3 position, Quaternion rotation){
GameObject obj = GameObject.Instantiate(lightningPrefab, position, rotation);
/* Directly after instantiating the Object
* you can already "mark" it to be destroyed after x seconds
* so you don't have to store it as variable anywhere */
GameObject.Destroy(obj, delay);
}
}
You then also could add some check to not constantly spawn the prefab:
[...]
private GameObject lightningObject;
public void OnShooting(Vector3 position, Quaternion rotation){
if(lightningObject == null ){
lightningObject = GameObject.Instantiate(lightningPrefab, position, rotation);
GameObject.Destroy(lightningObject, delay);
}
}
On this way there is always only one of your lightning objects a time.
Second Solution - Timeout
Another way without having to instantiate and destroy the object all the time would be a simple timeout instead of the Coroutine:
public class Shooting : MonoBehavior
{
[Tooltip("The lightning Object")]
[SerializeField]
private GameObject lightningObject;
[Tooltip("The time in sec the lightningObject stays visible")]
[SerializeField]
private float visibleDelay;
/* track the time that passed since the last OnShooting call */
private float timePassed;
/* Additional bool to not perform Update when not needed */
private bool isVisible;
/* Update is called once each frame */
private void Update(){
/* If the object is not visible do nothing */
if (isVisible != true) return;
/* update the timePassed */
timePassed += Time.deltaTime;
/* if delay passed since last OnShooting call
* deactiavte the object */
if (timePassed >= visibleDelay){
lightningObject.SetActive(false);
}
}
public void OnShooting(){
/* Activate the Object */
lightningObject.SetActive(true);
/* set isVisible */
isVisible = true;
/* reset the timePassed */
timePassed = 0;
}
}
Hmm. Your code works fine in my project.
What i'm doing, some object have your script and I deactivate and then activate the gameObject when scene is playing.
Your Destroy Method is public.
Check your project, maybe somewhere calls StopAllCoroutines() or StopCoroutine(DestroyMethod());

OnAreaTouched stacking Andengine

First I will show you image to explain my problem
Description of image:
I have 2 sprites RED and white .I attached
Red Sprite with Scene and
White Sprite with Red Sprite
I have moved and scaled it Red Sprite and white sprite like in 2nd image
My Problem
I have registered touch listener.But I want to register touch of white sprite when full image is scaled (after 2nd image case)
But when i register touch on fully scale it doesn't trigger touch .
To trigger touch i have to register both sprites touch before image 1
I have also seen similar problem here .
My code
> `titleScene = new Scene();
titleScene.setBackground(new Background(0, 1, 0));
A_Background_Sprite = new Sprite(0, 0, A_Background_TextureRegion, activity.getVertexBufferObjectManager());
titleScene.attachChild(A_Background_Sprite);
RED_Sprite = new Sprite(50, 50, RED_TextureRegion, activity.getVertexBufferObjectManager()){
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
if(!RED_Sprite.isScaled())
{
Log.i("Apple_Background_Sprite", "setOnClickListener");
AppleX=(int) RED_Sprite.getX();
AppleY= (int) RED_Sprite.getY();
RED_Sprite.registerEntityModifier(new SequenceEntityModifier(new MoveModifier(1f, RED_Sprite.getX(), camera.getCenterX(), RED_Sprite.getY(),camera.getCenterY()),new ScaleModifier(1f, 1f, 2f, new IEntityModifierListener() {
public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
// TODO Auto-generated method stub
white_Sprite.setVisible(true);
titleScene.registerTouchArea(white_Sprite);
}
public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
// TODO Auto-generated method stub
}
},EaseLinear.getInstance())));
}
else
{
// Spelling_Background_Sprite.registerEntityModifier(new MoveModifier(4f, camera.getWidth(), 20, 400, 400));
}
return true;
// here you can use the code
}
};
RED_Sprite.setSize(150f, 150f);
titleScene.setTouchAreaBindingOnActionDownEnabled(true);
white_Sprite.setVisible(false);
titleScene.attachChild(RED_Sprite);
RED_Sprite.attachChild(white_Sprite);
titleScene.registerTouchArea(RED_Sprite);
PLease Take a look at
RED_Sprite.registerEntityModifier(new SequenceEntityModifier(new MoveModifier(1f, RED_Sprite.getX(), camera.getCenterX(), RED_Sprite.getY(),camera.getCenterY()),new ScaleModifier(1f, 1f, 2f, new IEntityModifierListener() {
public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
// TODO Auto-generated method stub
white_Sprite.setVisible(true);
titleScene.registerTouchArea(white_Sprite);
}
When you have overlying objects, and you want to trigger touch events on all of them, be sure you don't return true at the end of the onTouch callback function, otherwise the touch listener stops processing the remaining touch events. See this tutorial for more info http://andengineguides.wordpress.com/2011/09/14/getting-started-touch-events/