When I look(focusing gazepointer over cube) on the cube teleport (vanishes and then come to new place), I want to add some time delay between its teleport activity.
1.)Teleport.cs
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(Collider))]
public class Teleport : MonoBehaviour {
private Vector3 startingPosition;
void Start() {
startingPosition = transform.localPosition;
SetGazedAt(false);
}
public void SetGazedAt(bool gazedAt) {
GetComponent<Renderer>().material.color = gazedAt ? Color.green : Color.red;
}
public void Reset() {
transform.localPosition = startingPosition;
}
public void ToggleVRMode() {
Cardboard.SDK.VRModeEnabled = !Cardboard.SDK.VRModeEnabled;
}
public void TeleportRandomly() {
Vector3 direction = Random.onUnitSphere;
direction.y = Mathf.Clamp(direction.y, 0.5f, 1f);
float distance = 2 * Random.value + 1.5f;
transform.localPosition = direction * distance;
}
}
2.)Teleportlegacy.cs
using UnityEngine;
using System.Collections;
public class TeleportLegacyUI : Teleport {
private CardboardHead head;
void Awake() {
head = Camera.main.GetComponent<StereoController>().Head;
CardboardOnGUI.IsGUIVisible = true;
CardboardOnGUI.onGUICallback += this.OnGUI;
}
void Update() {
RaycastHit hit;
bool isLookedAt = GetComponent<Collider>().Raycast(head.Gaze, out hit, Mathf.Infinity);
SetGazedAt(isLookedAt);
if (Cardboard.SDK.Triggered && isLookedAt) {
print("gazed");
///maaaaibbbbbbbnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
TeleportRandomly();
//Update2();
}
}
void OnGUI() {
if (!CardboardOnGUI.OKToDraw(this)) {
return;
}
if (GUI.Button(new Rect(50, 50, 200, 50), "Reset")) {
Reset();
}
if (GUI.Button(new Rect(50, 110, 200, 50), "Recenter")) {
Cardboard.SDK.Recenter();
}
if (GUI.Button(new Rect(50, 170, 200, 50), "VR Mode")) {
ToggleVRMode();
}
}
void OnDestroy() {
CardboardOnGUI.onGUICallback -= this.OnGUI;
}
}
How should I make the time delay between the teleport activity of cube?
I'd suggest a coroutine, you might need to add a flag or something to avoid it getting double triggered (you could reset it at the end of the coroutine)
public IEnumerator TeleportCoroutine()
{
yield return new WaitForSeconds(3.5f);
Vector3 direction = Random.onUnitSphere;
direction.y = Mathf.Clamp(direction.y, 0.5f, 1f);
float distance = 2 * Random.value + 1.5f;
transform.localPosition = direction * distance;
}
public void TeleportRandomly() {
StartCoroutine(TeleportCoroutine());
}
Edit: If you'd like the object to warp after being gazed at for a certain amount of time, try:
using UnityEngine;
using System.Collections;
public class TeleportLegacyUI : Teleport {
private CardboardHead head;
private float gazeTotalTime = 0;
void Awake()
{
head = Camera.main.GetComponent<StereoController>().Head;
CardboardOnGUI.IsGUIVisible = true;
CardboardOnGUI.onGUICallback += this.OnGUI;
}
void Update() {
RaycastHit hit;
bool isLookedAt = GetComponent<Collider>().Raycast(head.Gaze, out hit, Mathf.Infinity);
SetGazedAt(isLookedAt);
if(isLookedAt)
gazeTotalTime += Time.deltaTime;
else
gazeTotalTime = 0;
if(gazeTotalTime > 1.0f)
TeleportRandomly();
}
void OnGUI() {
if (!CardboardOnGUI.OKToDraw(this)) {
return;
}
if (GUI.Button(new Rect(50, 50, 200, 50), "Reset")) {
Reset();
}
if (GUI.Button(new Rect(50, 110, 200, 50), "Recenter")) {
Cardboard.SDK.Recenter();
}
if (GUI.Button(new Rect(50, 170, 200, 50), "VR Mode")) {
ToggleVRMode();
}
}
void OnDestroy() {
CardboardOnGUI.onGUICallback -= this.OnGUI;
}
}
Related
im trying to create an android plugin and import it in unity but i always get 0 as return value from the plugin method and i cant fix this issue.
Here is what i did:
AndroidStudio:
-Created a new project
-Created a library module (package: com.e.timerlibrary)
-Created Public Class "MyPlugin"
-Build -> "Make Module 'timerlibrary'"
-copied "classes.jar" file into "Assets/Plugins/Android" in Unity
MyPlugin only has one method:
public int testmethode(){
return 100;
}
Unity:
AndroidJavaObject JavaTimerClass = new AndroidJavaObject("com.e.timerlibrary.MyPlugin");
TextPlugin.text = JavaTimerClass.Call<int>("testmethode").ToString();
TextPlugin.text should display "100" but its always 0.
It seems like the name of the package cant be found
Hopefully someone can help me. Im new to unity&Androidstudio and followed many tutorials on youtube but i cant fix this issue.
Here is my full c# code. it's basically a timer.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CountDownTimer : MonoBehaviour
{
public float timeValue = 0;
public float timeValuePause = 0;
public float sliderValue;
public Slider slider;
public Text textTimer;
public Text textTimerBtn;
public Text TextPlugin;
bool timerActive = false;
bool backTimerActive = false;
AndroidJavaObject JavaTimerClass = new AndroidJavaObject("com.e.timerlibrary.MyPlugin");
int testvar1;
// Start is called before the first frame update
void Start()
{
textTimer.text = timeValue.ToString();
//startService();
}
// Update is called once per frame
void Update()
{
if (timerActive)
{
timeValue -= Time.deltaTime;
textTimer.text = timeValue.ToString("f0");
slider.value = timeValue;
if (timeValue <= 0)
{
timerActive = false;
textTimerBtn.text = "Start";
timeValue = 0;
slider.interactable = true;
}
}
}
public void OnTimerBtnClick()
{
textTimerBtn.text = timerActive ? "Start" : "Stop";
timerActive = !timerActive;
slider.interactable = false;
if (timerActive==false)
{
timeValue = 0;
textTimer.text = timeValue.ToString("f0");
slider.interactable = true;
slider.value = 0;
}
}
public void GetValueOfSlider(float value)
{
if (timerActive == false)
{
textTimer.text = value.ToString("f0");
timeValue = value;
}
}
void OnApplicationPause(bool pause) //Wird nur jeweils 1 mal ausgeführt!!
{
if (pause)
{
//startService1();
//TextPlugin.text = "pause";
TextPlugin.text = JavaTimerClass.Call<int>("testmethode").ToString();
}
else
{
//TextPlugin.text = "unpause";
stopService1();
}
}
void startService1()
{
/* if (!backTimerActive)
{
JavaTimerClass.Call("StartTimerService");
backTimerActive = true;
} */
TextPlugin.text = JavaTimerClass.Call<int>("testmethode").ToString();
//TextPlugin.text = JavaTimerClass.Call<int>("GetTime").ToString();
}
void stopService1()
{
//TextPlugin.text = JavaTimerClass.Call<int>("StopTimerService").ToString();
backTimerActive = false;
}
}
here is java code:
package com.e.timerlibrary;
public class MyPlugin {
public int testmethode(){
return 100;
}
}
i know it looks pretty bad but im only trying to get the plugin to work
I am developing an image viewer app on android platform using QT. The image viewer has the functions of moving to the next image and moving to the previous image by clicking buttons.
I am using the QStringList::const_iterator to control the method of moving. However, only the function of moving to the next image can be successfully implemented, while the function of moving to the previous image fails to work. The code addPixmap(*m_imageIt); cannot be added into the
relative button's function. Otherwise, the app will get stopped. Please help me.
showpic.h
#ifndef SHOWPIC_H
#define SHOWPIC_H
#include <QWidget>
#include <QTimer>
namespace Ui {
class ShowPic;
}
class ShowPic : public QWidget
{
Q_OBJECT
public:
explicit ShowPic(QWidget *parent = 0);
~ShowPic();
public:
void addPixmap(const QPixmap &pixmap);
void startPlay(QStringList infilenames);
private slots:
void on_pushButton_3_clicked();
void tick();
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_4_clicked();
private:
Ui::ShowPic *ui;
QStringList::const_iterator m_imageIt;
QTimer m_timer;
QStringList filenames;
bool flag = false;
};
#endif // SHOWPIC_H
showpic.cpp
#include "showpic.h"
#include "ui_showpic.h"
ShowPic::ShowPic(QWidget *parent) :
QWidget(parent),
ui(new Ui::ShowPic)
{
ui->setupUi(this);
m_timer.setInterval(1000);
connect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
}
ShowPic::~ShowPic()
{
delete ui;
}
void ShowPic::tick(){
addPixmap(*m_imageIt);
m_imageIt ++;
if(m_imageIt == filenames.end()){
m_imageIt = filenames.begin();
}
}
void ShowPic::addPixmap(const QPixmap &pixmap){
ui->graphicsView->setScene(new QGraphicsScene);
ui->graphicsView->scene()->addPixmap(pixmap);
ui->graphicsView->fitInView(ui->graphicsView->scene()->itemsBoundingRect() ,Qt::KeepAspectRatio);
}
void ShowPic::startPlay(QStringList infilenames){
filenames = infilenames;
m_imageIt = filenames.begin();
m_timer.start();
flag == false;
QString d("Stop");
ui->pushButton_3->setText(d);
}
void ShowPic::on_pushButton_3_clicked() //play
{
if(flag == false){
m_timer.stop();
QString d("Play");
ui->pushButton_3->setText(d);
flag = true;
}else{
m_timer.start();
QString d("Stop");
ui->pushButton_3->setText(d);
flag = false;
}
}
void ShowPic::on_pushButton_clicked() //move to the prev image
{
if(!filenames.isEmpty()){
m_timer.stop();
m_imageIt--;
if(m_imageIt != filenames.begin()){
addPixmap(*m_imageIt);
}else{
m_imageIt = filenames.end();
//addPixmap(*m_imageIt); //????
}
}
}
void ShowPic::on_pushButton_2_clicked() //move to the next image
{
if(!filenames.isEmpty()){
m_timer.stop();
m_imageIt++;
if(m_imageIt != filenames.end()){
addPixmap(*m_imageIt);
}else{
m_imageIt = filenames.begin();
addPixmap(*m_imageIt);
}
}
}
I have changed the code using the integer way. Finally, it works now.
showpic.h
#ifndef SHOWPIC_H
#define SHOWPIC_H
#include <QWidget>
#include <QTimer>
namespace Ui {
class ShowPic;
}
class ShowPic : public QWidget
{
Q_OBJECT
public:
explicit ShowPic(QWidget *parent = 0);
~ShowPic();
public:
void addPixmap(const QPixmap &pixmap);
void startPlay(QStringList infilenames);
private slots:
void on_pushButton_3_clicked();
void tick();
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_4_clicked();
private:
Ui::ShowPic *ui;
//QStringList::const_iterator m_imageIt;
int index;
QTimer m_timer;
QStringList filenames;
bool flag = false;
};
#endif // SHOWPIC_H
showpic.cpp
#include "showpic.h"
#include "ui_showpic.h"
ShowPic::ShowPic(QWidget *parent) :
QWidget(parent),
ui(new Ui::ShowPic)
{
ui->setupUi(this);
m_timer.setInterval(1000);
connect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
index = 0;
}
ShowPic::~ShowPic()
{
delete ui;
}
void ShowPic::tick(){
addPixmap(QPixmap(filenames.at(index)));
index++;
if(index == filenames.size()){
index = 0;
}
}
void ShowPic::addPixmap(const QPixmap &pixmap){
ui->graphicsView->setScene(new QGraphicsScene);
//ui->graphicsView->setScene(ui->graphicsView->scene());
ui->graphicsView->scene()->addPixmap(pixmap);
ui->graphicsView->fitInView(ui->graphicsView->scene()->itemsBoundingRect() ,Qt::KeepAspectRatio);
}
void ShowPic::startPlay(QStringList infilenames){
filenames = infilenames;
//m_imageIt = filenames.begin();
index = 0;
m_timer.start();
flag == false;
QString d("Stop");
ui->pushButton_3->setText(d);
}
void ShowPic::on_pushButton_3_clicked()
{
if(flag == false){
m_timer.stop();
QString d("Play");
ui->pushButton_3->setText(d);
flag = true;
}else{
m_timer.start();
QString d("Stop");
ui->pushButton_3->setText(d);
flag = false;
}
}
void ShowPic::on_pushButton_clicked() //prev
{
if(!filenames.isEmpty()){
m_timer.stop();
index--;
if(index < 0){
index = filenames.size()-1;
addPixmap(QPixmap(filenames.at(index)));
}else{
//
addPixmap(QPixmap(filenames.at(index)));
}
}
}
void ShowPic::on_pushButton_2_clicked() //next
{
if(!filenames.isEmpty()){
m_timer.stop();
index++;
if(index != filenames.size()){
addPixmap(QPixmap(filenames.at(index)));
}else{
//
index = 0;
addPixmap(QPixmap(filenames.at(index)));
}
}
}
Just connect it with your timers:
enum Direction
{
Forward = 1,
Backward = -1,
};
class ImageProvider
{
public:
ImageProvider( const QStringList& data )
: _data( data )
{ Q_ASSERT( !data.IsEmpty(); ) }
void Next()
{
_current += _direction;
Loop();
}
void Prev()
{
_current -= _direction;
Loop();
}
const QString& Current() const
{
return _data[_current];
}
void SetDirection( Direction direction )
{
_direction = direction;
}
void Reverse()
{
SetDirection( _direction != Forward ? Forward : Backward );
}
private:
void Loop()
{
if ( _current < 0 )
_current = _data.size() - 1;
if ( _current >= _data.size() )
_current = 0;
}
private:
Direction _direction = Forward;
int _current = 0;
const QStringList& _data;
};
I am trying to generate a depth map from the point cloud. I know that I can project the point cloud to the image plane, however there is already a function (ScreenCoordinateToWorldNearestNeighbor) in the TangoSupport script that finds the XYZ point given a screen coordinate.
I am unable to get this support function to work, and it seems that one or more of my inputs are invalid. I am updating my depthmap texture in the OnTangoDepthAvailable event.
public void OnTangoDepthAvailable(TangoUnityDepth tangoDepth)
{
_depthAvailable = true;
Matrix4x4 ccWorld = _Camera.transform.localToWorldMatrix;
bool isValid = false;
Vector3 colorCameraPoint = new Vector3();
for (int i = 0; i < _depthMapSize; i++)
{
for (int j = 0; j < _depthMapSize; j++)
{
if (TangoSupport.ScreenCoordinateToWorldNearestNeighbor(
_PointCloud.m_points, _PointCloud.m_pointsCount,
tangoDepth.m_timestamp,
_ccIntrinsics,
ref ccWorld,
new Vector2(i / (float)_depthMapSize, j / (float)_depthMapSize),
out colorCameraPoint, out isValid) == Common.ErrorType.TANGO_INVALID)
{
_depthTexture.SetPixel(i, j, Color.red);
continue;
}
if (isValid)
{
//_depthTexture.SetPixel(i, j, new Color(colorCameraPoint.z, colorCameraPoint.z, colorCameraPoint.z));
_depthTexture.SetPixel(i, j,
new Color(0,UnityEngine.Random.value,0));
}
else
{
_depthTexture.SetPixel(i, j, Color.white);
}
}
}
_depthTexture.Apply();
_DepthMapQuad.material.mainTexture = _depthTexture;
}
If I had to guess, I would say that I am passing in the wrong matrix (ccWorld). Here is what it says in the documents for the matrix param:
Transformation matrix of the color camera with respect to the Unity
world frame.
The result is a white depth map, which means that the function is returning successfully, however the isValid is false meaning that it couldn't find any nearby point cloud point after projection.
Any ideas? Also I noticed that the performance is pretty bad, even when my depth map is 8x8. Should I not be updating the depthmap when ever new depth data is available (inside OnTangoDepthAvailable)?
Edit:
I was able to make the function return successfully, however now it doesn't find a point cloud point nearby after projection. The resulting depth map is always white. I am printing out all the arguments, and it all looks correct, so I think I am passing in the wrong matrix.
You should update your SDK and Project Tango Dev Kit. Here is an example of getting depth map on Android, perhaps you get a hint for unity:
public class MainActivity extends AppCompatActivity {
private Tango mTango;
private TangoConfig mTangoConfig;
private TangoPointCloudManager mPointCloudManager;
private AtomicBoolean tConnected = new AtomicBoolean(false);
Random rand = new Random();
private ImageView imageDepthMap;
private static final ArrayList<TangoCoordinateFramePair> framePairs = new ArrayList<TangoCoordinateFramePair>();
{
framePairs.add(new TangoCoordinateFramePair(
TangoPoseData.COORDINATE_FRAME_CAMERA_DEPTH,
TangoPoseData.COORDINATE_FRAME_DEVICE));
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//initialize the imageView
imageDepthMap = (ImageView)findViewById(R.id.imageView);
//initialize pointCloudManager
mPointCloudManager = new TangoPointCloudManager();
}
#Override
protected void onResume(){
super.onResume();
//obtain the tango configuration
if(tConnected.compareAndSet(false, true)) {
try {
setTango();
} catch (TangoOutOfDateException tE) {
tE.printStackTrace();
}
}
}
#Override
protected void onPause(){
super.onPause();
if(tConnected.compareAndSet(true, false)) {
try {
//disconnect Tango service so other applications can use it
mTango.disconnect();
} catch (TangoException e) {
e.printStackTrace();
}
}
}
private void setTango(){
mTango = new Tango(MainActivity.this, new Runnable() {
#Override
public void run() {
TangoSupport.initialize();
mTangoConfig = new TangoConfig();
mTangoConfig = mTango.getConfig(TangoConfig.CONFIG_TYPE_CURRENT);
mTangoConfig.putBoolean(TangoConfig.KEY_BOOLEAN_DEPTH, true); //activate depth sensing
mTango.connect(mTangoConfig);
mTango.connectListener(framePairs, new Tango.OnTangoUpdateListener() {
#Override
public void onPoseAvailable(TangoPoseData tangoPoseData) {
}
#Override
public void onXyzIjAvailable(TangoXyzIjData pointCloud) {
// Log.d("gDebug", "xyZAvailable");
//TangoXyzIjData pointCloud = mPointCloudManager.getLatestXyzIj();
// Update current camera pose
if (pointCloud.ijRows * pointCloud.ijCols > 0){
try {
// Calculate the last camera color pose.
TangoPoseData lastFramePose = TangoSupport.getPoseAtTime(0,
TangoPoseData.COORDINATE_FRAME_START_OF_SERVICE,
TangoPoseData.COORDINATE_FRAME_CAMERA_COLOR,
TangoSupport.TANGO_SUPPORT_ENGINE_OPENGL, 0);
if (pointCloud != null) {
//obtain depth info per pixel
TangoSupport.DepthBuffer depthBuf = TangoSupport.upsampleImageNearestNeighbor(pointCloud, mTango.getCameraIntrinsics(TangoCameraIntrinsics.TANGO_CAMERA_COLOR), lastFramePose);
//create Depth map
int[] intBuff = convertToInt(depthBuf.depths, depthBuf.width, depthBuf.height);
final Bitmap Image = Bitmap.createBitmap(intBuff, depthBuf.width, depthBuf.height, Bitmap.Config.ARGB_8888);
runOnUiThread(new Runnable() {
#Override
public void run() {
imageDepthMap.setImageBitmap(Image);
}
});
}
} catch (TangoErrorException e) {
Log.e("gDebug", "Could not get valid transform");
}
}
}
#Override
public void onFrameAvailable(int i) {
//Log.d("gDebug", "Frame Available from " + i);
}
#Override
public void onTangoEvent(TangoEvent tangoEvent) {
}
});
}
});
}
private int[] convertToInt(FloatBuffer pointCloudData, int width, int height){
double mulFact = 255.0/5.0;
int byteArrayCapacity = width * height;
int[] depthMap = new int[byteArrayCapacity];
int grayPixVal = 0;
pointCloudData.rewind();
for(int i =0; i < byteArrayCapacity; i++){
//obtain grayscale representation
grayPixVal = (int)(mulFact * (5.0- pointCloudData.get(i)));
depthMap[i] = Color.rgb(grayPixVal, grayPixVal, grayPixVal);
}
return depthMap;
}
}
I extracted this code from my already working version. Try to fix any config related errors. The code assumes depth sensing range of 0.4m - 5m in depth estimation. Mapping zero to 255 allows regions which were not estimated (value of zero) to be white.
Im making a jumper game. The objetive is stay alive jumping platforms.
I start the game with my character and 3 platforms. The next platforms I generate randomly with a timerhandler.
Its almost ready but Im facing some problems with a timerhandler.
Im using it to spawn platforms (static bodys) once every second.
private void addPlat(int x, int y)
{
platform = new Platform(x, y, vbom, physicsWorld);
attachChild(platform);
}
private void createPlatSpawn()
{
float mEffectSpawnDelay = 1f;
platSpawnTimerHandler = new TimerHandler(mEffectSpawnDelay, true, new ITimerCallback()
{
#Override
public void onTimePassed(TimerHandler pTimerHandler) {
platformList.add(platform);
if (platformList.getLast().getY() >= 240 && platformList.getLast().getY() < 400)
{
yCoord = (int) (platform.getY() - addNumber.nextInt(160));
}
else if (platformList.getLast().getY() < 240 && platformList.getLast().getY() >= 50)
{
yCoord = (int) (platform.getY() + addNumber.nextInt(160));
}
xCoord = (int) (platform.getX() + 200);
addPlat(xCoord, yCoord);
}
});
resourcesManager.engine.registerUpdateHandler(platSpawnTimerHandler);
}
To jump I use a variable footContacts, when its positive it can jump, otherwise it cant
Here the contact listener
private ContactListener contactListener()
{
ContactListener contactListener = new ContactListener()
{
public void beginContact(Contact contact)
{
final Fixture x1 = contact.getFixtureA();
final Fixture x2 = contact.getFixtureB();
if (x1.getBody().getUserData() != null && x2.getBody().getUserData() != null)
{
if (x2.getBody().getUserData().equals("player"))
{
player.increaseFootContacts();
}
}
}
public void endContact(Contact contact)
{
final Fixture x1 = contact.getFixtureA();
final Fixture x2 = contact.getFixtureB();
if (x1.getBody().getUserData() != null && x2.getBody().getUserData() != null)
{
if (x2.getBody().getUserData().equals("player"))
{
player.decreaseFootContacts();
}
}
}
public void preSolve(Contact contact, Manifold oldManifold)
{
}
public void postSolve(Contact contact, ContactImpulse impulse)
{
}
};
return contactListener;
}
Here is the method inside the class Player, to make him jump
public void jump()
{
if (footContacts < 1)
{
return;
}
body.setLinearVelocity(new Vector2(body.getLinearVelocity().x, 15));
}
The first 3 platforms the jump action works perfectly but when he interact with the platforms created by the timerhandler, it doesnt work. Anyone can help me?
Adding the method to create the first 3 platforms:
private void createFirstPlat()
{
addPlat(200, 200);
addPlat(400, 300);
addPlat(600, 150);
}
Class Platform
public class Platform extends Sprite{
private Body body;
public Platform(float pX, float pY, VertexBufferObjectManager vbo, PhysicsWorld physicsWorld)
{
super(pX, pY, ResourcesManager.getInstance().platform_region, vbo);
createPhysics(physicsWorld);
// TODO Auto-generated constructor stub
}
private void createPhysics (PhysicsWorld physicsWorld)
{
body = PhysicsFactory.createBoxBody(physicsWorld, this, BodyType.StaticBody, PhysicsFactory.createFixtureDef(0, 0, 0.5f));
body.setUserData("platform");
physicsWorld.registerPhysicsConnector(new PhysicsConnector(this, body, true, false)
{
#Override
public void onUpdate(float pSecondsElapsed)
{
super.onUpdate(pSecondsElapsed);
}
});
}
}
You should have post more code where you manually crate those 3 working platforms. It's possible that the problem is in .setUserData which I can't see because you haven't posted your Platform class as well.
Another possible problem is that you don't attach it to right entity or there is a problem with physiscsConnector which you maybe don't initialize. Try to create
public Entity foregroundLayer = new Entity();
and attach it to the scene. Then in addPlat use
foregroundLayer.attachChild(platform)
If that won't help please paste your Platform class and how you create them for first three times.
PS By the way, it's great solution when you want to control layers. For example you want some sprites to be on top and some sprites to be on background while overlapping. The important thing is attaching order so you first attach backgroundLayer and then foregroundLayer. Finally you can attach other entites for those two layers at any time and it will be shown as you expect.
I have been using google maps api v2 for around a month.
Aside from the other bugs reported in the issue tracker I came across this following odd bug.
java.lang.IllegalStateException: Camera moved during a cancellation
which happens inside a CancelableCallback that I use for the animateCamera method.
The exception is traced back to the user touch event.
I believe this happens because the user is performing an interaction with the map while the onFinish/onCancel is being called now this does not happen often however it is quite irritating.
Is there anyway around this issue? I would appreciate any help you can provide.
Here is a complete code:
public void moveMapToSearchMarker(
final T fmMarker,
final FriendlyMapGoogleMapMarkerClickListener fmMarkerClickListener,
float zoomLevel) {
CameraUpdate camUpdate = CameraUpdateFactory.newLatLngZoom(fmMarker
.getMarker().getPosition(), zoomLevel);
getGoogleMap().animateCamera(camUpdate, new CancelableCallback() {
#Override
public void onFinish() {
setMarkerOnSearchComplete(fmMarker, fmMarkerClickListener);
}
#Override
public void onCancel() {
setMarkerOnSearchComplete(fmMarker, fmMarkerClickListener);
}
});
}
private void setMarkerOnSearchComplete(T fmMarker,
FriendlyMapGoogleMapMarkerClickListener fmMarkerClickListener) {
if (!fmMarker.getMarker().isVisible())
fmMarker.getMarker().setVisible(true);
for (T lstFmMarker : this)
lstFmMarker.setSearched(false);
fmMarker.setSearched(true);
createOrUpdateSearchMarker(fmMarker.getMarker().getPosition());
fmMarkerClickListener.onFriendlyMapMarkerClick(fmMarker, this, true);
}
public void createOrUpdateSearchMarker(LatLng searchMarkerPos) {
if (searchRadiusCircle == null) {
CircleOptions cOpts = new CircleOptions();
int strokeColor = getSearchRadiusColor() + 0xEE000000;
cOpts.center(searchMarkerPos).fillColor(getSearchRadiusColor())
.strokeColor(strokeColor).radius(12).strokeWidth(2F);
searchRadiusCircle = getGoogleMap().addCircle(cOpts);
} else {
searchRadiusCircle.setVisible(true);
searchRadiusCircle.setCenter(searchMarkerPos);
}
}
public <T extends FriendlyMapMarker> boolean onFriendlyMapMarkerClick(
T fmMarker, FriendlyMapMarkerList fmMarkerList,
boolean isOnCancelableCallback) {
FriendlyMapMarkerAndList fmMapMarkerAndList = new FriendlyMapMarkerAndList<FriendlyMapMarker, FriendlyMapMarkerList>();
fmMapMarkerAndList.fmMarker = fmMarker;
fmMapMarkerAndList.fmMarkerList = fmMarkerList;
return handleMarkerClick(fmMapMarkerAndList, isOnCancelableCallback);
}
private boolean handleMarkerClick(
FriendlyMapMarkerAndList fmMapMarkerAndList,
boolean isOnCancelableCallback) {
if (fmMapMarkerAndList == null)
return false;
final FriendlyMapMarker fmMarker = fmMapMarkerAndList.fmMarker;
Marker marker = fmMarker.getMarker();
final FriendlyMapMarkerList fmMarkerList = fmMapMarkerAndList.fmMarkerList;
if (fmMarker != null) {
if (fmMarker.getClass().equals(FriendlyMapPlaceMarker.class)) {
balloonActions.setCurrentFmMarker(fmMarker);
balloonActions.setPlaceLikeButtonVisibility();
CancelableCallback onCameraCompleteMove = new CancelableCallback() {
#Override
public void onFinish() {
openActionBalloon(fmMarker, fmMarkerList);
}
#Override
public void onCancel() {
openActionBalloon(fmMarker, fmMarkerList);
}
};
LatLng camPos = Utils.getRoundedLatLng(fmMarkerList
.getGoogleMap().getCameraPosition().target, 1e5);
LatLng markerPos = Utils.getRoundedLatLng(marker.getPosition(),
1e5);
if (!Utils.latLngEqualsByCoords(camPos, markerPos)
&& !isOnCancelableCallback)
fmMarkerList.getGoogleMap()
.animateCamera(
CameraUpdateFactory.newLatLng(fmMarker
.getLatLng()), 350,
onCameraCompleteMove);
else
onCameraCompleteMove.onFinish();
fmMarker.getMarker().showInfoWindow();
LoadAsyncBalloonExtendedStatisticsResult loadAsyncBalloonStatisticsResult = new LoadAsyncBalloonExtendedStatisticsResult(
activity, marker,
(FriendlyMapPlaceMarkerList) fmMarkerList);
loadAsyncBalloonStatisticsResult
.execute(((FriendlyMapPlaceMarker) fmMarker)
.getKnownLocationID());
return true;
}
if (fmMarker.getClass().equals(FriendlyMapDiscussionMarker.class)) {
balloonActionsDiscussion.setCurrentFmMarker(fmMarker);
final FriendlyMapDiscussionMarker fmdMarker = (FriendlyMapDiscussionMarker) fmMarker;
LatLng camPos = Utils.getRoundedLatLng(fmMarkerList
.getGoogleMap().getCameraPosition().target, 1e5);
LatLng markerPos = Utils.getRoundedLatLng(fmdMarker.getMarker()
.getPosition(), 1e5);
if (!Utils.latLngEqualsByCoords(camPos, markerPos)
&& !isOnCancelableCallback) {
CameraUpdate camUpdate = CameraUpdateFactory
.newLatLng(fmdMarker.getMarker().getPosition());
fmMarkerList.getGoogleMap().animateCamera(camUpdate, 350,
new CancelableCallback() {
#Override
public void onFinish() {
openWindowInfoActionBalloon(fmMarkerList,
fmdMarker);
}
#Override
public void onCancel() {
openWindowInfoActionBalloon(fmMarkerList,
fmdMarker);
}
});
} else {
openWindowInfoActionBalloon(fmMarkerList, fmdMarker);
}
return true;
}
if (fmMarker.getClass().equals(FriendlyMapThoughtMarker.class)) {
balloonActionThought.setCurrentFmMarker(fmMarker);
balloonActionThought.setDeleteButtonVisiblity();
final FriendlyMapThoughtMarker fmtMarker = (FriendlyMapThoughtMarker) fmMarker;
LatLng camPos = Utils.getRoundedLatLng(fmMarkerList
.getGoogleMap().getCameraPosition().target, 1e5);
LatLng markerPos = Utils.getRoundedLatLng(fmtMarker.getMarker()
.getPosition(), 1e5);
if (!Utils.latLngEqualsByCoords(camPos, markerPos)
&& !isOnCancelableCallback) {
CameraUpdate camUpdate = CameraUpdateFactory
.newLatLng(fmtMarker.getMarker().getPosition());
fmMarkerList.getGoogleMap().animateCamera(camUpdate, 350,
new CancelableCallback() {
#Override
public void onFinish() {
openWindowInfoActionBalloon(fmMarkerList,
fmtMarker);
}
#Override
public void onCancel() {
openWindowInfoActionBalloon(fmMarkerList,
fmtMarker);
}
});
} else {
openWindowInfoActionBalloon(fmMarkerList, fmtMarker);
}
return true;
}
}
return false;
}
private void openWindowInfoActionBalloon(
FriendlyMapMarkerList fmMarkerList, FriendlyMapMarker fmMarker) {
Marker m = fmMarker.getMarker();
m.showInfoWindow();
openActionBalloon(fmMarker, fmMarkerList);
}
private void openActionBalloon(FriendlyMapMarker marker,
FriendlyMapMarkerList fmMarkerList) {
Projection proj = fmMarkerList.getGoogleMap().getProjection();
Point markerScreenPoint = proj.toScreenLocation(marker.getMarker()
.getPosition());
if (marker.getClass().equals(FriendlyMapPlaceMarker.class)) {
balloonActionsDiscussion.setVisibility(View.INVISIBLE);
balloonActionThought.setVisibility(View.INVISIBLE);
setBalloonDimension(balloonActions, markerScreenPoint);
} else if (marker.getClass().equals(FriendlyMapDiscussionMarker.class)) {
balloonActions.setVisibility(View.INVISIBLE);
balloonActionThought.setVisibility(View.INVISIBLE);
setBalloonDimension(balloonActionsDiscussion, markerScreenPoint);
} else if (marker.getClass().equals(FriendlyMapThoughtMarker.class)) {
balloonActionsDiscussion.setVisibility(View.INVISIBLE);
balloonActions.setVisibility(View.INVISIBLE);
setBalloonDimension(balloonActionThought, markerScreenPoint);
}
}
private void setBalloonDimension(View ballonActionView,
Point markerScreenPoint) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) ballonActionView
.getLayoutParams();
int marginX = markerScreenPoint.x - (ballonActionView.getWidth() / 2);
int marginY = markerScreenPoint.y;
params.setMargins(marginX, marginY, -marginX, -marginY);
params.gravity = Gravity.NO_GRAVITY;
ballonActionView.setLayoutParams(params);
ballonActionView.setVisibility(View.VISIBLE);
}
I'd suggest posting that bug with stacktrace to the tracker.
at com.google.android.gms.maps.GoogleMap.animateCamera(Unknown Source)
at com.saipex.friendly_map.map_view_related_v2.FriendlyMapGoogleMapMarkerClickListener.handleMarkerClick(FriendlyMapGoogleMapMarkerClickListener.java:259)
at com.saipex.friendly_map.map_view_related_v2.FriendlyMapGoogleMapMarkerClickListener.onFriendlyMapMarkerClick(FriendlyMapGoogleMapMarkerClickListener.java:133)
at com.saipex.friendly_map.map_view_related_v2.model.FriendlyMapMarkerList.setMarkerOnSearchComplete(FriendlyMapMarkerList.java:163)
at com.saipex.friendly_map.map_view_related_v2.model.FriendlyMapMarkerList.access$0(FriendlyMapMarkerList.java:155)
at com.saipex.friendly_map.map_view_related_v2.model.FriendlyMapMarkerList$1.onCancel(FriendlyMapMarkerList.java:181)
It looks like you are trying something forbidden: animating camera in onCancel. The code would show us more.