I am following article on MS page about Custom map renderer and I can not get it to work for android. Map shows but pins (Markers) are not there. I did not found what I did different from official documents (as in previous link). When I debug, there are 3 markers in customPins collection. And custom renderer works in UWP. So issue is only in Android code.
Here is my CustomRender code for Android which does not shows pins.
using System;
using System.Collections.Generic;
using Android.Content;
using Android.Gms.Maps;
using Android.Gms.Maps.Model;
using Android.Widget;
using iVanApp;
using iVanApp.Android.CustomMapRenderers;
using iVanApp.Droid;
using iVanApp.Model;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.Android;
[assembly: ExportRenderer(typeof(NightMap), typeof(MapRenderers))]
namespace iVanApp.Android.CustomMapRenderers
{
public class MapRenderers : MapRenderer, GoogleMap.IInfoWindowAdapter
{
List<NightPin> customPins;
public MapRenderers(Context context) : base(context)
{
}
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
NativeMap.InfoWindowClick -= OnInfoWindowClick;
}
if (e.NewElement != null)
{
var formsMap = (NightMap)e.NewElement;
customPins = formsMap.NightPins;
}
}
protected override void OnMapReady(GoogleMap map)
{
base.OnMapReady(map);
NativeMap.InfoWindowClick += OnInfoWindowClick;
NativeMap.SetInfoWindowAdapter(this);
}
protected override MarkerOptions CreateMarker(Pin pin)
{
var marker = new MarkerOptions();
marker.SetPosition(new LatLng(pin.Position.Latitude, pin.Position.Longitude));
marker.SetTitle(pin.Label);
marker.SetSnippet(pin.Address);
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.pin));
return marker;
}
void OnInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)
{
var customPin = GetCustomPin(e.Marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (!string.IsNullOrWhiteSpace(customPin.Name))
{
}
}
NightPin GetCustomPin(Marker annotation)
{
var position = new Position(annotation.Position.Latitude, annotation.Position.Longitude);
foreach (var pin in customPins)
{
if (pin.Position == position)
{
return pin;
}
}
return null;
}
public global::Android.Views.View GetInfoContents(Marker marker)
{
var inflater = global::Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as global::Android.Views.LayoutInflater;
if (inflater != null)
{
global::Android.Views.View view;
var customPin = GetCustomPin(marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
view = inflater.Inflate(Resource.Layout.mtrl_layout_snackbar_include, null);
if (customPin.Name.Equals("Xamarin"))
{
view = inflater.Inflate(Resource.Layout.XamarinMapInfoWindow, null);
}
else
{
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
}
var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);
if (infoTitle != null)
{
infoTitle.Text = marker.Title;
}
if (infoSubtitle != null)
{
infoSubtitle.Text = marker.Snippet;
}
return view;
}
return null;
}
public global::Android.Views.View GetInfoWindow(Marker marker)
{
return null;
}
}
}
DOes anyone have idea why this would not work?
Note: I had to modify official MS code because I got errors. Wherever is Android.Views.View I had to modify it to global::Android.Views.View otherwise I got following error
"'MapRenderers' does not implement interface member
'GoogleMap.IInfoWindowAdapter.GetInfoContents(Marker)'.
'MapRenderers.GetInfoContents(Marker)' cannot implement
'GoogleMap.IInfoWindowAdapter.GetInfoContents(Marker)' because it does
not have the matching return type of 'View'.".
and
The type or namespace name 'Views' does not exist in the namespace
'iVanApp.Android' (are you missing an assembly reference?)
Hope this did not break my code.
After investigating and reading about custom map issues (and mostly solutions) from others I got a workaround solution how to get pins on map but does not show info window when I click on pin(marker). Here I found workaround. If I modify OnMapReday and call&add method SetMapMarkers then pins are visible but as I said no info window is shown when I click on pin
protected override void OnMapReady(GoogleMap map)
{
base.OnMapReady(map);
NativeMap.InfoWindowClick += OnInfoWindowClick;
NativeMap.SetInfoWindowAdapter(this);
SetMapMarkers();
}
private void SetMapMarkers()
{
NativeMap.Clear();
foreach (var pin in customPins)
{
NativeMap.AddMarker(CreateMarker(pin));
}
}
Although this is solution, I would prefer if I could get it to work without this workaround. Hence I did not put much effort why info window is not shown when you click on pin. In case there would be no solution without this workaround then I will be interested in solution with workaround but as I said I do not prefer to go this way.
As FreakyAli said that adding a custom pin and positions for CustomMap.
<local:CustomMap x:Name="customMap" MapType="Street" />
Adding a custom pin and positions the map's view with the MoveToRegion method
public MainPage()
{
InitializeComponent();
var pin = new CustomPin
{
Type = PinType.Place,
Position = new Position(37.79752, -122.40183),
Label = "Xamarin San Francisco Office",
Address = "394 Pacific Ave, San Francisco CA",
Id = "Xamarin",
Url = "http://xamarin.com/about/"
};
customMap.CustomPins = new List<CustomPin> { pin };
customMap.Pins.Add(pin);
customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183), Distance.FromMiles(1.0)));
}
I can get InfoWindow by clicking map pin, having no problem.
So hi to #ll this is my fist post/question on stackoverflow :D
I need help # following :
So i integrated the Facebook SDk sucessfully in my game but i´dont get the profile picture working ...
So i tryied it oldshool on Facebooks "Tutotial" Way and followed all steps to implement login functions and so on ...
I´ve downloaded the "friendsmash_start" Sample and implemented that Stuff ...
My Main Problem is i don´t get ahead with this problem and can´t figure out what i´m doing wrong so i´m hoping for help.
Here´s the complete Code from the MainMenu Script from the sample which is the only i´ve changed ... like in the tutorial ...
Unity shows me this Error -> "The name 'LoadPicture' does not exist in the current context ... so the errors are on these two parts of code :
"LoadPicture(Util.GetPictureURL("me", 128, 128), MyPictureCallback);" in the "OnLoggedIn" function
"LoadPicture(Util.GetPictureURL("me", 128, 128), MyPictureCallback);" in the "MyPictureCallback" function
I don´t understand it cause i searched myself in the script for this function "LoadPicture" and find nothing that was ... according to the "Tutorial" of facebook here :
https://developers.facebook.com/docs/games/unity/unity-tutorial?locale=de_DE
the function should be there cause they wrote there :
"Take a look at the LoadPicture method also in MainMenu.cs to see how we use the Unity WWW class to load the image returned by the graph API."
But i can´t find it :(
HOPE SOMEONE CAN HELP ME I DON´T GET IT ...
Have that problem unfortunately very long time ... thats enoying. :(
HERE`S THE FULL CODE OF MAINMENU.CS :
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Facebook.MiniJSON;
using System;
public class MainMenu : MonoBehaviour
{
// Inspector tunable members //
public Texture ButtonTexture;
public Texture PlayTexture; // Texture for main menu button icons
public Texture BragTexture;
public Texture ChallengeTexture;
public Texture StoreTexture;
public Texture FullScreenTexture;
public Texture FullScreenActiveTexture;
public Texture ResourcesTexture;
public Vector2 CanvasSize; // size of window on canvas
public Rect LoginButtonRect; // Position of login button
public Vector2 ResourcePos; // position of resource indicators (not used yet)
public Vector2 ButtonStartPos; // position of first button in main menu
public float ButtonScale; // size of main menu buttons
public float ButtonYGap; // gap between buttons in main menu
public float ChallengeDisplayTime; // Number of seconds the request sent message is displayed for
public Vector2 ButtonLogoOffset; // Offset determining positioning of logo on buttons
public float TournamentStep; // Spacing between tournament entries
public float MouseScrollStep = 40; // Amount score table moves with each step of the mouse wheel
public PaymentDialog paymentDialog;
public GUISkin MenuSkin;
public int CoinBalance;
public int NumLives;
public int NumBombs;
public Texture[] CelebTextures;
public string [] CelebNames;
// Private members //
private static MainMenu instance;
private static List<object> friends = null;
private static Dictionary<string, string> profile = null;
private static List<object> scores = null;
private static Dictionary<string, Texture> friendImages = new Dictionary<string, Texture>();
private Vector2 scrollPosition = Vector2.zero;
private bool haveUserPicture = false;
private float tournamentLength = 0;
private int tournamentWidth = 512;
private int mainMenuLevel = 0; // Level index of main menu
private string popupMessage;
private float popupTime;
private float popupDuration;
void Awake()
{
Util.Log("Awake");
paymentDialog = ((PaymentDialog)(GetComponent("PaymentDialog")));
// allow only one instance of the Main Menu
if (instance != null && instance != this)
{
Destroy(gameObject);
return;
}
#if UNITY_WEBPLAYER
// Execute javascript in iframe to keep the player centred
string javaScript = #"
window.onresize = function() {
var unity = UnityObject2.instances[0].getUnity();
var unityDiv = document.getElementById(""unityPlayerEmbed"");
var width = window.innerWidth;
var height = window.innerHeight;
var appWidth = " + CanvasSize.x + #";
var appHeight = " + CanvasSize.y + #";
unity.style.width = appWidth + ""px"";
unity.style.height = appHeight + ""px"";
unityDiv.style.marginLeft = (width - appWidth)/2 + ""px"";
unityDiv.style.marginTop = (height - appHeight)/2 + ""px"";
unityDiv.style.marginRight = (width - appWidth)/2 + ""px"";
unityDiv.style.marginBottom = (height - appHeight)/2 + ""px"";
}
window.onresize(); // force it to resize now";
Application.ExternalCall(javaScript);
#endif
DontDestroyOnLoad(gameObject);
instance = this;
// Initialize FB SDK
FB.Init(SetInit, OnHideUnity);
}
private void SetInit()
{
Util.Log("SetInit");
enabled = true; // "enabled" is a property inherited from MonoBehaviour
if (FB.IsLoggedIn)
{
Util.Log("Already logged in");
OnLoggedIn();
}
}
private void OnHideUnity(bool isGameShown)
{
Util.Log("OnHideUnity");
if (!isGameShown)
{
// pause the game - we will need to hide
Time.timeScale = 0;
}
else
{
// start the game back up - we're getting focus again
Time.timeScale = 1;
}
}
private void QueryScores()
{
FB.API("/app/scores?fields=score,user.limit(20)", Facebook.HttpMethod.GET, ScoresCallback);
}
private int getScoreFromEntry(object obj)
{
Dictionary<string,object> entry = (Dictionary<string,object>) obj;
return Convert.ToInt32(entry["score"]);
}
void ScoresCallback(FBResult result)
{
Util.Log("ScoresCallback");
if (result.Error != null)
{
Util.LogError(result.Error);
return;
}
scores = new List<object>();
List<object> scoresList = Util.DeserializeScores(result.Text);
foreach(object score in scoresList)
{
var entry = (Dictionary<string,object>) score;
var user = (Dictionary<string,object>) entry["user"];
string userId = (string)user["id"];
if (string.Equals(userId,FB.UserId))
{
// This entry is the current player
int playerHighScore = getScoreFromEntry(entry);
Util.Log("Local players score on server is " + playerHighScore);
if (playerHighScore < GameStateManager.Score)
{
Util.Log("Locally overriding with just acquired score: " + GameStateManager.Score);
playerHighScore = GameStateManager.Score;
}
entry["score"] = playerHighScore.ToString();
GameStateManager.HighScore = playerHighScore;
}
scores.Add(entry);
if (!friendImages.ContainsKey(userId))
{
// We don't have this players image yet, request it now
LoadPictureAPI(Util.GetPictureURL(userId, 128, 128),pictureTexture =>
{
if (pictureTexture != null)
{
friendImages.Add(userId, pictureTexture);
}
});
}
}
// Now sort the entries based on score
scores.Sort(delegate(object firstObj,
object secondObj)
{
return -getScoreFromEntry(firstObj).CompareTo(getScoreFromEntry(secondObj));
}
);
}
void OnApplicationFocus( bool hasFocus )
{
Util.Log ("hasFocus " + (hasFocus ? "Y" : "N"));
}
// Convenience function to check if mouse/touch is the tournament area
private bool IsInTournamentArea (Vector2 p)
{
return p.x > Screen.width-tournamentWidth;
}
// Scroll the tournament view by some delta
private void ScrollTournament(float delta)
{
scrollPosition.y += delta;
if (scrollPosition.y > tournamentLength - Screen.height)
scrollPosition.y = tournamentLength - Screen.height;
if (scrollPosition.y < 0)
scrollPosition.y = 0;
}
// variables for keeping track of scrolling
private Vector2 mouseLastPos;
private bool mouseDragging = false;
void Update()
{
if(Input.touches.Length > 0)
{
Touch touch = Input.touches[0];
if (IsInTournamentArea (touch.position) && touch.phase == TouchPhase.Moved)
{
// dragging
ScrollTournament (touch.deltaPosition.y*3);
}
}
if (Input.GetAxis("Mouse ScrollWheel") < 0)
{
ScrollTournament (MouseScrollStep);
}
else if (Input.GetAxis("Mouse ScrollWheel") > 0)
{
ScrollTournament (-MouseScrollStep);
}
if (Input.GetMouseButton(0) && IsInTournamentArea(Input.mousePosition))
{
if (mouseDragging)
{
ScrollTournament (Input.mousePosition.y - mouseLastPos.y);
}
mouseLastPos = Input.mousePosition;
mouseDragging = true;
}
else
mouseDragging = false;
}
// Button drawing logic //
private Vector2 buttonPos; // Keeps track of where we've got to on the screen as we draw buttons
private void BeginButtons()
{
// start drawing buttons at the chosen start position
buttonPos = ButtonStartPos;
}
private bool DrawButton(string text, Texture texture)
{
// draw a single button and update our position
bool result = GUI.Button(new Rect (buttonPos.x,buttonPos.y, ButtonTexture.width * ButtonScale, ButtonTexture.height * ButtonScale),text,MenuSkin.GetStyle("menu_button"));
Util.DrawActualSizeTexture(ButtonLogoOffset*ButtonScale+buttonPos,texture,ButtonScale);
buttonPos.y += ButtonTexture.height*ButtonScale + ButtonYGap;
if (paymentDialog.DialogEnabled)
result = false;
return result;
}
void OnGUI()
{
GUI.skin = MenuSkin;
if (Application.loadedLevel != mainMenuLevel) return; // don't display anything except when in main menu
GUILayout.Box("", MenuSkin.GetStyle("panel_welcome"));
if (!FB.IsLoggedIn)
{
GUI.Label((new Rect(179, 11, 287, 160)), "Login to Facebook", MenuSkin.GetStyle("text_only"));
if (GUI.Button(LoginButtonRect, "", MenuSkin.GetStyle("button_login")))
{
FB.Login("email,publish_actions", LoginCallback);
}
}
if (FB.IsLoggedIn)
{
string panelText = "Welcome ";
panelText += (!string.IsNullOrEmpty(GameStateManager.Username)) ? string.Format("{0}!", GameStateManager.Username) : "Smasher!";
if (GameStateManager.UserTexture != null)
GUI.DrawTexture( (new Rect(8,10, 150, 150)), GameStateManager.UserTexture);
GUI.Label( (new Rect(179 , 11, 287, 160)), panelText, MenuSkin.GetStyle("text_only"));
}
string subTitle = "Let's smash some friends!";
if (GameStateManager.Score > 0)
{
subTitle = "Score: " + GameStateManager.Score.ToString();
}
if (!string.IsNullOrEmpty(subTitle))
{
GUI.Label( (new Rect(132, 28, 400, 160)), subTitle, MenuSkin.GetStyle("sub_title"));
}
BeginButtons();
if (DrawButton("Play",PlayTexture))
{
onPlayClicked();
}
if (FB.IsLoggedIn)
{
// Draw resources bar
Util.DrawActualSizeTexture(ResourcePos,ResourcesTexture);
Util.DrawSimpleText(ResourcePos + new Vector2(47,5) ,MenuSkin.GetStyle("resources_text"),string.Format("{0}",CoinBalance));
Util.DrawSimpleText(ResourcePos + new Vector2(137,5) ,MenuSkin.GetStyle("resources_text"),string.Format("{0}",NumBombs));
Util.DrawSimpleText(ResourcePos + new Vector2(227,5) ,MenuSkin.GetStyle("resources_text"),string.Format("{0}",NumLives));
}
#if UNITY_WEBPLAYER
if (Screen.fullScreen)
{
if (DrawButton("Full Screen",FullScreenActiveTexture))
SetFullscreenMode(false);
}
else
{
if (DrawButton("Full Screen",FullScreenTexture))
SetFullscreenMode(true);
}
#endif
DrawPopupMessage();
}
public void AddPopupMessage(string message, float duration)
{
popupMessage = message;
popupTime = Time.realtimeSinceStartup;
popupDuration = duration;
}
public void DrawPopupMessage()
{
if (popupTime != 0 && popupTime + popupDuration > Time.realtimeSinceStartup)
{
// Show message that we sent a request
Rect PopupRect = new Rect();
PopupRect.width = 800;
PopupRect.height = 100;
PopupRect.x = Screen.width / 2 - PopupRect.width / 2;
PopupRect.y = Screen.height / 2 - PopupRect.height / 2;
GUI.Box(PopupRect,"",MenuSkin.GetStyle("box"));
GUI.Label(PopupRect, popupMessage, MenuSkin.GetStyle("centred_text"));
}
}
void TournamentGui()
{
GUILayout.BeginArea(new Rect((Screen.width - 450),0,450,Screen.height));
// Title box
GUI.Box (new Rect(0, - scrollPosition.y, 100,200), "", MenuSkin.GetStyle("tournament_bar"));
GUI.Label (new Rect(121 , - scrollPosition.y, 100,200), "Tournament", MenuSkin.GetStyle("heading"));
Rect boxRect = new Rect();
if(scores != null)
{
var x = 0;
foreach(object scoreEntry in scores)
{
Dictionary<string,object> entry = (Dictionary<string,object>) scoreEntry;
Dictionary<string,object> user = (Dictionary<string,object>) entry["user"];
string name = ((string) user["name"]).Split(new char[]{' '})[0] + "\n";
string score = "Smashed: " + entry["score"];
boxRect = new Rect(0, 121+(TournamentStep*x)-scrollPosition.y , 100,128);
// Background box
GUI.Box(boxRect,"",MenuSkin.GetStyle("tournament_entry"));
// Text
GUI.Label (new Rect(24, 136 + (TournamentStep * x) - scrollPosition.y, 100,128), (x+1)+".", MenuSkin.GetStyle("tournament_position")); // Rank e.g. "1.""
GUI.Label (new Rect(250,145 + (TournamentStep * x) - scrollPosition.y, 300,100), name, MenuSkin.GetStyle("tournament_name")); // name
GUI.Label (new Rect(250,193 + (TournamentStep * x) - scrollPosition.y, 300,50), score, MenuSkin.GetStyle("tournament_score")); // score
Texture picture;
if (friendImages.TryGetValue((string) user["id"], out picture))
{
GUI.DrawTexture(new Rect(118,128+(TournamentStep*x)-scrollPosition.y,115,115), picture); // Profile picture
}
x++;
}
}
else GUI.Label (new Rect(180,270,512,200), "Loading...", MenuSkin.GetStyle("text_only"));
// Record length so we know how far we can scroll to
tournamentLength = boxRect.y + boxRect.height + scrollPosition.y;
GUILayout.EndArea();
}
// React to menu buttons //
private void onPlayClicked()
{
Util.Log("onPlayClicked");
if (friends != null && friends.Count > 0)
{
// Select a random friend and get their picture
Dictionary<string, string> friend = Util.RandomFriend(friends);
GameStateManager.FriendName = friend["first_name"];
GameStateManager.FriendID = friend["id"];
GameStateManager.CelebFriend = -1;
LoadPictureURL(friend["image_url"],FriendPictureCallback);
}
else
{
//We can't access friends
GameStateManager.CelebFriend = UnityEngine.Random.Range(0,CelebTextures.Length - 1);
GameStateManager.FriendName = CelebNames[GameStateManager.CelebFriend];
}
// Start the main game
Application.LoadLevel("GameStage");
GameStateManager.Instance.StartGame();
}
public void SetFullscreenMode (bool on)
{
if (on)
{
Screen.SetResolution (Screen.currentResolution.width, Screen.currentResolution.height, true);
}
else
{
Screen.SetResolution ((int)CanvasSize.x, (int)CanvasSize.y, false);
}
}
public static void FriendPictureCallback(Texture texture)
{
GameStateManager.FriendTexture = texture;
}
delegate void LoadPictureCallback (Texture texture);
IEnumerator LoadPictureEnumerator(string url, LoadPictureCallback callback)
{
WWW www = new WWW(url);
yield return www;
callback(www.texture);
}
void LoadPictureAPI (string url, LoadPictureCallback callback)
{
FB.API(url,Facebook.HttpMethod.GET,result =>
{
if (result.Error != null)
{
Util.LogError(result.Error);
return;
}
var imageUrl = Util.DeserializePictureURLString(result.Text);
StartCoroutine(LoadPictureEnumerator(imageUrl,callback));
});
}
void LoadPictureURL (string url, LoadPictureCallback callback)
{
StartCoroutine(LoadPictureEnumerator(url,callback));
}
void LoginCallback(FBResult result)
{
Util.Log("LoginCallback");
if (FB.IsLoggedIn)
{
OnLoggedIn();
}
}
void OnLoggedIn()
{
Util.Log("Logged in. ID: " + FB.UserId);
// Reqest player info and profile picture
FB.API("/me?fields=id,first_name,friends.limit(100).fields(first_name,id)", Facebook.HttpMethod.GET, APICallback);
LoadPicture(Util.GetPictureURL("me", 128, 128), MyPictureCallback);
}
void APICallback(FBResult result)
{
Util.Log("APICallback");
if (result.Error != null)
{
Util.LogError(result.Error);
// Let's just try again
FB.API("/me?fields=id,first_name,friends.limit(100).fields(first_name,id)", Facebook.HttpMethod.GET, APICallback);
return;
}
profile = Util.DeserializeJSONProfile(result.Text);
GameStateManager.Username = profile["first_name"];
friends = Util.DeserializeJSONFriends(result.Text);
}
void MyPictureCallback(Texture texture)
{
Util.Log("MyPictureCallback");
if (texture == null)
{
// Let's just try again
LoadPicture(Util.GetPictureURL("me", 128, 128), MyPictureCallback);
return;`
}
GameStateManager.UserTexture = texture;
}
}
change the word "LoadPicture" for "LoadPictureAPI".
For reference see:
https://github.com/fbsamples/friendsmash-unity/blob/master/friendsmash_payments_start/Assets/Scripts/MainMenu.cs
I am a new developer in cocos2dx.I am developing a game in which i am using the box2d bodies that are loading through physics editor.There are more than 20 bodies using in a level of the game,that i am making separate body for separate sprite attached with them and the similar bodies are used in the other levels and there are 50 levels in the game and for each level,i have made separate class and again making the b2body loading function,all the code is working properly but I just want to make a generic function for loading the bodies in a class so that i can use the same b2body loading function in all the levels.Also i have to destroy the particular body and the sprite on touching the sprite
//Sprites:
rect_sprite1=CCSprite::create("rect1.png");
rect_sprite1->setScaleX(rX);
rect_sprite1->setScaleY(rY);
this->addChild(rect_sprite1,1);
rect_sprite2=CCSprite::create("rect2.png");
rect_sprite2->setScaleX(rX);
rect_sprite2->setScaleY(rY);
this->addChild(rect_sprite2,1);
rect_sprite3=CCSprite::create("circle.png");
rect_sprite3->setScale(rZ);
this->addChild(rect_sprite3,1);
GB2ShapeCache::sharedGB2ShapeCache()->addShapesWithFile("obs.plist");
//body loading function
void Level1::addNewSpriteWithCoords()
{
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
b2BodyDef bodyDef1;
bodyDef1.type=b2_dynamicBody;
bodyDef1.position.Set((winSize.width*0.38)/PTM_RATIO,(winSize.height*0.4) /PTM_RATIO);
bodyDef1.userData = rect_sprite1;
body1 = (MyPhysicsBody*)world->CreateBody(&bodyDef1);
body1->setTypeFlag(7);
// add the fixture definitions to the body
GB2ShapeCache *sc1 = GB2ShapeCache::sharedGB2ShapeCache();
sc1->addFixturesToBody(body1,"rect1", rect_sprite1);
rect_sprite1->setAnchorPoint(sc1->anchorPointForShape("rect1"));
b2BodyDef bodyDef2;
bodyDef2.type=b2_dynamicBody;
bodyDef2.position.Set((winSize.width*0.62)/PTM_RATIO,
(winSize.height*0.4)/PTM_RATIO);
bodyDef2.userData = rect_sprite2;
body2 = (MyPhysicsBody*)world->CreateBody(&bodyDef2);
body2->setTypeFlag(7);
// add the fixture definitions to the body
GB2ShapeCache *sc2 = GB2ShapeCache::sharedGB2ShapeCache();
sc2->addFixturesToBody(body2,"rect2", rect_sprite2);
rect_sprite2->setAnchorPoint(sc2->anchorPointForShape("rect2"));
b2BodyDef bodyDef3;
bodyDef3.type=b2_dynamicBody;
bodyDef3.position.Set((winSize.width*0.5)/PTM_RATIO, (winSize.height*0.23)/PTM_RATIO);
bodyDef3.userData = rect_sprite3;
body3 = (MyPhysicsBody*)world->CreateBody(&bodyDef3);
body3->setTypeFlag(7);
// add the fixture definitions to the body
GB2ShapeCache *sc3 = GB2ShapeCache::sharedGB2ShapeCache();
sc3->addFixturesToBody(body3,"circle", rect_sprite3);
rect_sprite3->setAnchorPoint(sc3->anchorPointForShape("circle"));
}
void Level1::ccTouchesBegan(cocos2d::CCSet* touches, cocos2d::CCEvent* event)
{
if(box->containsPoint(touchPoint))
{
this->removeChild(((CCSprite*)rect),true);
if(((CCSprite*)rect)==rect_sprite1)
{
rect_sprite1=NULL;
world->DestroyBody(body1);
Utils::setCount(Utils::getCount()-1);
}
if(((CCSprite*)rect)==rect_sprite2)
{
rect_sprite2=NULL;
world->DestroyBody(body2);
Utils::setCount(Utils::getCount()-1);
}
if(((CCSprite*)rect)==rect_sprite3)
{
rect_sprite3=NULL;
world->DestroyBody(body3);
Utils::setCount(Utils::getCount()-1);
}
}
Similarly i am doing for other levels.
If anyone know about it,please suggest.Thanks
This seems more like a "What design pattern should I use?" than a specific problem with loading the code.
In general, when I want to create "Entities" that require a physical body, I use a base class that contains the Box2D body as one of its members. The base class is a container for the body (which is assigned to it) and is responsible for destroying the body (removing it from the Box2D world) when the Entity is destroyed.
Derived classes can load the body from the Box2D shape cache. This is best shown through an example. There is a game I am working on where I have a swarm of different shaped asteroids circling a sun. Here is a screen shot:
The base class, Entity, contains the body and destroys it when the Entity is destroyed:
class Entity : public HasFlags
{
public:
enum
{
DEFAULT_ENTITY_ID = -1,
};
private:
uint32 _ID;
// Every entity has one "main" body which it
// controls in some way. Or not.
b2Body* _body;
// Every entity has a scale size from 1 to 100.
// This maps on to the meters size of 0.1 to 10
// in the physics engine.
uint32 _scale;
protected:
void SetScale(uint32 value)
{
assert(value >= 1);
assert(value <= 100);
_scale = value;
}
public:
void SetBody(b2Body* body)
{
assert(_body == NULL);
if(_body != NULL)
{
CCLOG("BODY SHOULD BE NULL BEFORE ASSIGNING");
_body->GetWorld()->DestroyBody(_body);
_body = NULL;
}
_body = body;
if(body != NULL)
{
_body->SetUserData(this);
for (b2Fixture* f = _body->GetFixtureList(); f; f = f->GetNext())
{
f->SetUserData(this);
}
}
}
inline void SetID(uint32 ID)
{
_ID = ID;
}
inline uint32 GetID() const
{
return _ID;
}
virtual string ToString(bool updateDescription = false)
{
string descr = "ID: ";
descr += _ID;
descr += "Flags: ";
if(IsFlagSet(HF_IS_GRAPH_SENSOR))
descr += "IS_FLAG_SENSOR ";
return descr;
}
Entity() :
_ID(DEFAULT_ENTITY_ID),
_body(NULL),
_scale(1)
{
}
Entity(uint32 flags, uint32 scale) :
HasFlags(flags),
_ID(DEFAULT_ENTITY_ID),
_body(NULL),
_scale(scale)
{
}
virtual void Update()
{
}
virtual void UpdateDisplay()
{
}
virtual ~Entity()
{
if(_body != NULL)
{
_body->GetWorld()->DestroyBody(_body);
}
}
inline static float32 ScaleToMeters(uint32 scale)
{
return 0.1*scale;
}
inline Body* GetBody()
{
return _body;
}
inline const Body* GetBody() const
{
return _body;
}
inline uint32 GetScale()
{
return _scale;
}
inline float32 GetSizeMeters()
{
return ScaleToMeters(_scale);
}
};
The Asteroid class itself is responsible for loading one of several different "Asteroid" shapes from the shape cache. However, ALL the asteroids have common logic for making them move about the center of the screen. They have a rope joint attached and the Update(...) function adds some "spin" to them so they rotate around the center:
class Asteroid : public Entity
{
private:
b2Fixture* _hull;
Vec2 _anchor;
CCSprite* _sprite;
float32 _targetRadius;
public:
// Some getters to help us out.
b2Fixture& GetHullFixture() const { return *_hull; }
float32 GetTargetRadius() { return _targetRadius; }
CCSprite* GetSprite() { return _sprite; }
void UpdateDisplay()
{
// Update the sprite position and orientation.
CCPoint pixel = Viewport::Instance().Convert(GetBody()->GetPosition());
_sprite->setPosition(pixel);
_sprite->setRotation(-CC_RADIANS_TO_DEGREES(GetBody()->GetAngle()));
}
virtual void Update()
{
Body* body = GetBody();
Vec2 vRadius = body->GetPosition();
Vec2 vTangent = vRadius.Skew();
vTangent.Normalize();
vRadius.Normalize();
// If it is not moving...give it some spin.
if(fabs(vTangent.Dot(body->GetLinearVelocity())) < 1)
{
body->SetLinearDamping(0.001);
body->ApplyForceToCenter(body->GetMass()*1.5*vTangent);
body->ApplyForce(vRadius,body->GetMass()*0.05*vRadius);
}
else
{
body->SetLinearDamping(0.05);
}
}
~Asteroid()
{
}
Asteroid() :
Entity(HF_CAN_MOVE | HF_UPDATE_PRIO_5,50)
{
}
bool Create(b2World& world, const string& shapeName,const Vec2& position, float32 targetRadius)
{
_targetRadius = targetRadius;
_anchor = position;
string str = shapeName;
str += ".png";
_sprite = CCSprite::createWithSpriteFrameName(str.c_str());
_sprite->setTag((int)this);
_sprite->setAnchorPoint(ccp(0.5,0.5));
// _sprite->setVisible(false);
b2BodyDef bodyDef;
bodyDef.position = position;
bodyDef.type = b2_dynamicBody;
Body* body = world.CreateBody(&bodyDef);
assert(body != NULL);
// Add the polygons to the body.
Box2DShapeCache::instance().addFixturesToBody(body, shapeName, GetSizeMeters());
SetBody(body);
return true;
}
};
The Create(...) function for the Asteroid is called from the loading code in the scene, which could easily be a .csv file with the shape names in it. It actually reuses the names several times (there are only about 10 asteroid shapes).
You will notice that the Asteroid also has a CCSprite associated with it. Not all Entities have a sprite, but some do. I could have created an Entity-Derived class (EntityWithSprite) for this case so that the sprite could be managed as well, but I try to avoid too many nested classes. I could have put it into the base class, and may still. Regardless, the Asteroids contain their own sprites and load them from the SpriteCache. They are updated in a different part of the code (not relevant here, but I will be happy to answer questions about it if you are curious).
NOTE: This is part of a larger code base and there are features like zooming, cameras, graph/path finding, and lots of other goodies in the code base. Feel free to use what you find useful.
You can find all the (iOS) code for this on github and there are videos and tutorials posted on my site here.
I'm implementing the NavigationTransition with the TransitionService provided by the Windows Phone 8 toolkit and Microsoft.Phone.Controls. I was expecting the pages to cross fade during the transition but they don't crossfade by default.
For instance if I'm going back to a previous page using a fade out transition, the origin page fades to full opacity before the target page appears, producing a "popping" effect.
I hoping that someone could provide guidance on getting that effect to happen.
Please check the type of your RootFrame in App.xaml.cs, it must be TransitionFrame if want to use NavigationTransition.
I ended up using some slight-of-hand with screen shots and the far background plane to make the phone pages appear to "cross-fade" - here with edited out biz-details:
public class FormPage : PhoneApplicationPage {
public FormPage() {
InitializeComponent();
PrepareAnimationIn(FormApp.frameTransition);
}
void PrepareAnimationIn(string pageAnimation) {
AnimatedPageFactory.SetNavigationInTransition(pageAnimation, this);
}
public void PrepareAnimationOut(string pageAnimation) {
AnimatedPageFactory.SetNavigationOutTransition(pageAnimation, this);
}
void StoreScreenShot(string name, WriteableBitmap bitmap) {
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) {
string path = Path.Combine(screenshotDir, name + screenFileType);
store.CreateDirectory(screenshotDir);
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(path, FileMode.Create, store)) {
using (BinaryWriter writer = new BinaryWriter(stream)) {
int count = bitmap.Pixels.Length * sizeof(int);
byte[] pixels = new byte[count];
Buffer.BlockCopy(bitmap.Pixels, 0, pixels, 0, count);
writer.Write(pixels, 0, pixels.Length);
}
}
}
}
WriteableBitmap FetchScreenShot(string name) {
WriteableBitmap bitmap = new WriteableBitmap((int)this.ActualWidth, (int)this.ActualHeight);
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) {
string path = Path.Combine(screenshotDir, name + screenFileType);
if (store.FileExists(path)) {
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(path, FileMode.Open, store)) {
using (BinaryReader reader = new BinaryReader(stream)) {
int count = bitmap.Pixels.Length * sizeof(int);
byte[] pixels = new byte[count];
reader.Read(pixels, 0, count);
Buffer.BlockCopy(pixels, 0, bitmap.Pixels, 0, count);
}
}
store.DeleteFile(path);
}
}
return bitmap;
}
WriteableBitmap ScreenShot() {
WriteableBitmap bmpCurrentScreenImage = new WriteableBitmap((int)this.ActualWidth, (int)this.ActualHeight);
bmpCurrentScreenImage.Render(_canvas, new MatrixTransform());
bmpCurrentScreenImage.Invalidate();
return bmpCurrentScreenImage;
}
ImageBrush ImageBrushFromBitmap(WriteableBitmap bitmap) {
return new ImageBrush { ImageSource = bitmap };
}
static Stack<string> formImages = new Stack<string>();
static string screenFileType = ".frmscn";
static string screenshotDir = "frmscrn";
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) {
var app = Application.Current as App;
if (e.NavigationMode == NavigationMode.New &&
e.Uri.ToString().Contains("FormPage.xaml")) {
WriteableBitmap screenShot = ScreenShot();
app.RootFrame.Background = ImageBrushFromBitmap(screenShot);
formImages.Push(Name);
StoreScreenShot(Name, screenShot);
} else if (e.NavigationMode == NavigationMode.Back) {
if (formImages.Count > 0)
app.RootFrame.Background = ImageBrushFromBitmap(FetchScreenShot(formImages.Pop()));
else {
//we're backing out of the last form so reset the background
app.RootFrame.Background = null;
RemoveCachedScreenshots();
}
}
}
public static void RemoveCachedScreenshots() {
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) {
string path = Path.Combine(screenshotDir, "*" + screenFileType);
try {
string[] fileList = store.GetFileNames(path);
foreach (string f in fileList) {
store.DeleteFile(Path.Combine(screenshotDir, f));
}
} catch {
}
}
}
}
I have a problem with intermediate image. The image is showing only once. After i move the image "line" is not showing anymore.
public void paintLine(Graphics g) {
if (line == null) {
line = new BufferedImage(1, height, BufferedImage.TYPE_INT_ARGB);
Graphics gImg = line.getGraphics();
float[] data = datas[index];
for (float f : data) {
float[] rgb = ColorMap.getPixelColor(f);
gImg.setColor(new Color(rgb[0], rgb[1], rgb[2]));
gImg.drawRect(0, (int)yPos--, 1, 1);
}
gImg.dispose();
}
xIncr++;
g.drawImage(line, (int)xPos - xIncr, (int)yPos, null);
graph.repaint();
}
This method is called in paintComponent ofJPanel.
If i recreate the image "line" each time, it is displaying properly with really poor performance.
Emm... I am not pretty sure owing to less information in your question but, as a rule, image may disappear because of doubleBuffered(false) option. So you need to set the double buffered option to true manually for your canvas. Code something like this
public class MyLabel extends JLabel{
public MyLabel()
{
this.setDoubleBuffered(true);
}
public void paintComponent(Graphics g)
{
this.paintLine(g);
}
public void paintLine(Graphics g) {
if (line == null) {
line = new BufferedImage(1, height, BufferedImage.TYPE_INT_ARGB);
Graphics gImg = line.getGraphics();
float[] data = datas[index];
for (float f : data) {
float[] rgb = ColorMap.getPixelColor(f);
gImg.setColor(new Color(rgb[0], rgb[1], rgb[2]));
gImg.drawRect(0, (int)yPos--, 1, 1);
}
//gImg.dispose();
}
xIncr++;
g.drawImage(line, (int)xPos - xIncr, (int)yPos, null);
graph.repaint();
}
}
Now I guess the conception is more clear
Good luck