How to setPosition menu from the screen? - menu

How can I set my menu Sprites in the center of the screen with the usual look for menu
CCSize size = CCDirector::sharedDirector()->getWinSize();
sprite ->setPosition(ccp(size.width, size.height));
Please help me with the (ccp(?,?))
Sprites: Start, Options, Quit for game menu
#include "MenuScene.h"
#include "cocos2d.h"
USING_NS_CC;
using namespace cocos2d;
CCSprite *car;
CCScene* MenuScene::scene()
{
CCScene *scene = CCScene::create();
MenuScene *layer = MenuScene::create();
scene->addChild(layer);
return scene;
}
// on "init" you need to initialize your instance
bool MenuScene::init()
{
// 1. super init first
if ( !CCLayer::init() )
{
return false;
}
this->setTouchEnabled(true);
//this->schedule( schedule_selector(MenuScene::update) );
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
CCSize size = CCDirector::sharedDirector()->getWinSize();
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
// add a "close" icon to exit the progress. it's an autorelease object
// CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
// "CloseNormal.png",
// "CloseSelected.png",
// this,
// menu_selector(MenuScene::menuCloseCallback));
//
// pCloseItem->setPosition(ccp(origin.x + visibleSize.width -
pCloseItem->getContentSize().width ,
// origin.y +
pCloseItem->getContentSize().height));
// create menu, it's an autorelease object
// CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
// pMenu->setPosition(CCPointZero);
// this->addChild(pMenu, 1);
// 3. add sprite below...
CCSprite *menuLayout = CCSprite::create("sky.png");
menuLayout->setPosition(ccp(size.width/2, size.height/2));
this->addChild(menuLayout, -1);
float aX = size.width / menuLayout->getContentSize().width;
float aY = size.height / menuLayout->getContentSize().height;
menuLayout->setScaleX(aX);
menuLayout->setScaleY(aY);
return true;
}
//callfuncN_selector(MainScene::spriteMoveFinished)
//backcalls the function spriteMoveFinished()
void MenuScene::spriteMoveFinished(CCNode* pSender)
{
CCSprite *sprite = (CCSprite *)pSender;
this->removeChild(sprite, true);
}
void MenuScene::Menus()
{
CCSize size = CCDirector::sharedDirector()->getWinSize();
CCMenuItemImage *startItem = CCMenuItemImage::create("sprite.png",
"sprite.png",this,menu_selector(MenuScene::menuCloseCallback));
startItem->setPosition(ccp(590, 450));
float aX = size.width / startItem->getContentSize().width;
float aY = size.height / startItem->getContentSize().height;
// startItem->setScaleX(aX);
// startItem->setScaleY(aY);
CCMenuItemImage *extraItem = CCMenuItemImage::create("sprite2.png",
"sprite2.png",this,menu_selector(MenuScene::menuCloseCallback));
extraItem->setPosition(ccp(590,350));
//float bX = size.width / extraItem->getContentSize().width;
//float bY = size.height / extraItem->getContentSize().height;
//extraItem->setScaleX(bX);
//extraItem->setScaleY(bY);
CCMenuItemImage *optionsItem = CCMenuItemImage::create("options.png",
"options.png",this,menu_selector(MenuScene::menuCloseCallback));
optionsItem->setPosition(ccp(590, 250));
//float cX = size.width / optionsItem->getContentSize().width;
//float cY = size.height / optionsItem->getContentSize().height;
//optionsItem->setScaleX(cX);
//optionsItem->setScaleY(cY);\
CCMenuItemImage *quitItem = CCMenuItemImage::create("quit.png",
"quit.png",this,menu_selector(MenuScene::menuCloseCallback));
quitItem->setPosition(ccp(590, 150));
// float dX = size.width / quitItem->getContentSize().width;
// float dY = size.height / quitItem->getContentSize().height;
// quitItem->setScaleX(dX);
// quitItem->setScaleY(dY);
CCMenu* pMenu = CCMenu::create(startItem, extraItem, optionsItem, quitItem,
NULL);
pMenu->setPosition(0,0);
this->addChild(pMenu, 0);
}
void MenuScene::ccTouchesBegan(cocos2d::CCSet* touches, cocos2d::CCEvent* event){
Menus();
}
void MenuScene::ccTouchesMoved(cocos2d::CCSet* touches, cocos2d::CCEvent* event){
Menus();
}
void MenuScene::ccTouchesEnded(cocos2d::CCSet* touches, cocos2d::CCEvent* event){
}
void MenuScene::ccTouchesCancelled(cocos2d::CCSet* touches, cocos2d::CCEvent*
event){
}
void MenuScene::menuCloseCallback(CCObject* pSender)
{
CCDirector::sharedDirector()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
/* namespace cocos2d */

If you wish to position the menu at the center of the screen you must provide the center co-ordinates in ccl
sprite ->setPosition(ccp(size.width/2, size.height/2));

First you get window size...
CGSize Window_size=[[CCDirector sharedDirector]winSize];
Now set CCMenuItem in CCMenu With position...
CCMenuItem *Minus_Menu_item = [CCMenuItemImage itemWithNormalImage:#"ButtonMinus.png" selectedImage:#"ButtonMinus.png" disabledImage:#"ButtonNum1.png" target:self selector:#selector(Minus_Button:)];
Minus_Menu_item.position=ccp(180, 200);
Menu_Minus=[CCMenu menuWithItems:Minus_Menu_item, nil];
Menu_Minus.position = CGPointZero;
[self addChild:Menu_Minus];

Related

Why is my stretchblt images losing colours?

I am having some difficulties in correctly populating a CListCtrl with thumbnails of monitor displays.
On the right of my CDialog I have a static control and I render the image on a white canvas like this:
void CCenterCursorOnScreenDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
if (nIDCtl == IDC_STATIC_MONITOR && !m_imgPreview.IsNull())
{
// Set the mode
SetStretchBltMode(lpDrawItemStruct->hDC, HALFTONE);
// Wipe the canvas
FillRect(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)));
// Get canvas rectangle
const CRect rectCanvas(lpDrawItemStruct->rcItem);
// Calculate ratio factors
const float nRatioImage = m_imgPreview.GetWidth() / static_cast<float>(m_imgPreview.GetHeight());
const float nRatioCanvas = rectCanvas.Width() / static_cast<float>(rectCanvas.Height());
// Calculate new rectangle size
// Account for portrait images (negative values)
CRect rectDraw = rectCanvas;
if (nRatioImage > nRatioCanvas)
rectDraw.SetRect(0, 0, rectDraw.right, static_cast<int>(rectDraw.right / nRatioImage));
else if (nRatioImage < nRatioCanvas)
rectDraw.SetRect(0, 0, static_cast<int>((rectDraw.bottom * nRatioImage)), rectDraw.bottom);
// Add a margin
rectDraw.DeflateRect(5, 5);
// Move to center
const CSize ptOffset = rectCanvas.CenterPoint() - rectDraw.CenterPoint();
rectDraw.OffsetRect(ptOffset);
// Add a black frame
FrameRect(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)));
// Draw
m_imgPreview.Draw(lpDrawItemStruct->hDC, rectDraw);
return;
}
CDialogEx::OnDrawItem(nIDCtl, lpDrawItemStruct);
}
The above works beautifully:
But I have problems with the CListCtrl versions of the images. For instance, I am losing the colouring as you can see.
My CImageList is created like this:
m_ImageListThumb.Create(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, ILC_COLOR32, 0, 1);
m_ListThumbnail.SetImageList(&m_ImageListThumb, LVSIL_NORMAL);
I then create all the thumbnails by calling DrawThumbnails() in OnInitDialog:
void CCenterCursorOnScreenDlg::DrawThumbnails()
{
int monitorIndex = 0;
m_ListThumbnail.SetRedraw(FALSE);
for (auto& strMonitor : m_monitors.strMonitorNames)
{
CImage img;
CreateMonitorThumbnail(monitorIndex, img, true);
CBitmap* pImage = new CBitmap();
pImage->Attach((HBITMAP)img);
m_ImageListThumb.Add(pImage, nullptr);
CString strMonitorDesc = m_monitors.strMonitorNames.at(monitorIndex);
strMonitorDesc.AppendFormat(L" (Screen %d)", monitorIndex + 1);
m_ListThumbnail.InsertItem(monitorIndex, strMonitorDesc, monitorIndex);
monitorIndex++;
delete pImage;
}
m_ListThumbnail.SetRedraw(TRUE);
}
The CreateMonitorThumbnail function:
BOOL CCenterCursorOnScreenDlg::CreateMonitorThumbnail(const int iMonitorIndex, CImage &rImage, bool bSmall)
{
const CRect rcCapture = m_monitors.rcMonitors.at(iMonitorIndex);
// destroy the currently contained bitmap to create a new one
rImage.Destroy();
auto nWidth = rcCapture.Width();
auto nHeight = rcCapture.Height();
if (bSmall)
{
nWidth = THUMBNAIL_WIDTH;
nHeight = THUMBNAIL_HEIGHT;
}
// create bitmap and attach it to this object
if (!rImage.Create(nWidth, nHeight, 32, 0))
{
AfxMessageBox(L"Cannot create image!", MB_ICONERROR);
return FALSE;
}
// create virtual screen DC
CDC dcScreen;
dcScreen.CreateDC(_T("DISPLAY"), nullptr, nullptr, nullptr);
// copy the contents from the virtual screen DC
BOOL bRet = FALSE;
if (bSmall)
{
CRect rt(0, 0, nWidth, nHeight);
//::FillRect(rImage.GetDC(), rt, static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)));
bRet = ::StretchBlt(rImage.GetDC(), 0, 0,
nWidth,
nHeight,
dcScreen.m_hDC,
rcCapture.left,
rcCapture.top,
rcCapture.Width(),
rcCapture.Height(), SRCCOPY | CAPTUREBLT);
}
else
{
bRet = ::BitBlt(rImage.GetDC(), 0, 0,
rcCapture.Width(),
rcCapture.Height(),
dcScreen.m_hDC,
rcCapture.left,
rcCapture.top, SRCCOPY | CAPTUREBLT);
}
// do cleanup and return
dcScreen.DeleteDC();
rImage.ReleaseDC();
return bRet;
}
Ideally I want to have exactly the same kind of visual image as on the right, but obviously resized down. How do I fix this?
I simplified the converting from CImage to CBitmap but it made no difference:
void CCenterCursorOnScreenDlg::DrawThumbnails()
{
int monitorIndex = 0;
// Stop redrawing the CListCtrl
m_ListThumbnail.SetRedraw(FALSE);
// Loop monitor info
for (auto& strMonitor : m_monitors.strMonitorNames)
{
// Create the thumbnail image
CImage monitorThumbnail;
CreateMonitorThumbnail(monitorIndex, monitorThumbnail, true);
// Convert it to a CBitmap
CBitmap* pMonitorThumbnailBitmap = CBitmap::FromHandle(monitorThumbnail);
// Add the CBitmap to the CImageList
m_ImageListThumb.Add(pMonitorThumbnailBitmap, nullptr);
// Build the caption description
CString strMonitorDesc = m_monitors.strMonitorNames.at(monitorIndex);
strMonitorDesc.AppendFormat(L" (Screen %d)", monitorIndex + 1);
// Add the item to the CListCtrl
m_ListThumbnail.InsertItem(monitorIndex, strMonitorDesc, monitorIndex);
monitorIndex++;
}
// Start redrawiung the CListCtrl again
m_ListThumbnail.SetRedraw(TRUE);
}
If I change my code to pass false for the last parameter, so that it uses the original captured images without scaling down:
The colours are god there, so it is when I do:
if (bSmall)
{
CRect rt(0, 0, nWidth, nHeight);
//::FillRect(rImage.GetDC(), rt, static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)));
bRet = ::StretchBlt(rImage.GetDC(), 0, 0,
nWidth,
nHeight,
dcScreen.m_hDC,
rcCapture.left,
rcCapture.top,
rcCapture.Width(),
rcCapture.Height(), SRCCOPY | CAPTUREBLT);
}
that it messes up.
My issue was did not have anything to do with OnDrawItem. I simply included that to indicate how the image on the right was being rendered. I thought it may helped as background information. But it has probably confused the question and I may take it out in the long run!
Based on the comments I was reminded about SetStretchBltMode which was missing from CreateMonitorThumbnail. So, I now have this function:
BOOL CCenterCursorOnScreenDlg::CreateMonitorThumbnail(const int iMonitorIndex, CImage &rImage, bool bResizeAsThumbnail)
{
const CRect rcCapture = m_monitors.rcMonitors.at(iMonitorIndex);
// Destroy the currently contained bitmap to create a new one
rImage.Destroy();
// Massage the dimensions as we want a thumbnail
auto nWidth = rcCapture.Width();
auto nHeight = rcCapture.Height();
if (bResizeAsThumbnail)
{
nWidth = m_iThumbnailWidth;
auto dRatio = rcCapture.Width() / nWidth;
//nHeight = m_iThumbnailHeight;
nHeight = static_cast<int>(rcCapture.Height() / dRatio);
if (nHeight > m_iThumbnailHeight)
{
AfxMessageBox(L"Need to investigate!");
}
}
// Create bitmap and attach it to this object
if (!rImage.Create(nWidth, nHeight, 32, 0))
{
AfxMessageBox(L"Cannot create image!", MB_ICONERROR);
return FALSE;
}
// Create virtual screen DC
CDC dcScreen;
dcScreen.CreateDC(L"DISPLAY", nullptr, nullptr, nullptr);
// Copy (or resize) the contents from the virtual screen DC
BOOL bRet = FALSE;
auto dcImage = rImage.GetDC();
if (bResizeAsThumbnail)
{
// Set the mode first!
SetStretchBltMode(dcImage, COLORONCOLOR);
CPen penBlack;
penBlack.CreatePen(PS_SOLID, 3, RGB(0, 0, 0));
::Rectangle(dcImage, 0, 0, m_iThumbnailWidth, m_iThumbnailHeight);
int iTop = (m_iThumbnailHeight - nHeight) / 2;
// Copy (and resize)
bRet = ::StretchBlt(dcImage, 0, iTop,
nWidth,
nHeight,
dcScreen.m_hDC,
rcCapture.left,
rcCapture.top,
rcCapture.Width(),
rcCapture.Height(), SRCCOPY | CAPTUREBLT);
}
else
{
// Copy
bRet = ::BitBlt(dcImage, 0, 0,
rcCapture.Width(),
rcCapture.Height(),
dcScreen.m_hDC,
rcCapture.left,
rcCapture.top, SRCCOPY | CAPTUREBLT);
}
// Do cleanup and return
dcScreen.DeleteDC();
rImage.ReleaseDC();
return bRet;
}
That was the key to getting the thumbnail showing with the right colours:

How to switch between 'scenes' using switch statement

so I'm creating an interactive story, and I want to switch between scenes by clicking buttons (like a standard old pokemon game except there isn't movement, just clicking).
I should probably use a switch statement right? But I don't know how to implement the changing of scenes and loading scenes into the cases. I also don't know if I would need to use 'if' statements within the cases.
This might be confusing, because it is very confusing to me. I'd appreciate any help you guys offer! I am desperate ;)
Code so far is below:
//PImages
PImage startScreen;
PImage[] waves = new PImage[3];
PImage[] scenes = new PImage[1];
int switchVariable;
//Objects
Button play;
void setup() {
size(750, 600);
background(#A3E9EA);
//Initialising Objects
play = new Button(50, 480, 330);
//loading wave images
waves[0] = loadImage("wave1.png");
waves[1] = loadImage("wave2.png");
waves[2] = loadImage("wave3.png");
//loading start image
startScreen = loadImage("start-screen.png");
//loading scenes
scenes[0] = loadImage("scene-one.png");
//setting frame rate
frameRate(6);
}
void draw() {
background(#A3E9EA);
frameCount++;
println (frameCount);
//drawing wave animation
if (frameCount < 5) {
image(waves[0], 0, 0);
}
else {
image(waves[1], 0, 0);
}
if (frameCount < 15 & frameCount > 10) {
background(#A3E9EA);
image(waves[2], 0, 0);
frameCount = 0;
}
//drawing start screen
image(startScreen, 0, 0);
//displaying play button
if (play.visible) play.buttonDisplay();
}
void mousePressed() {
if (play.visible) {
float d = dist(play.x+110, play.y+22, mouseX, mouseY);
if (d <= play.radius){
background(#A3E9EA);
image(scenes[0], 0, 0);
}
}
}
Button Class:
class Button {
float radius;
float x;
float y;
PImage[] buttonImage = new PImage[2];
boolean visible;
Button(float _radius, float _x, float _y) {
radius = _radius;
visible = true;
x = _x;
y = _y;
buttonImage[0] = loadImage("play-game-button.png");
}
void buttonDisplay() {
image(buttonImage[0], x, y);
}
}
The source code below shows one possible approach to your question. It does not rely on ‘switch’ but instead uses a custom control with up and down buttons similar to a Java stepper. The stepper control value corresponds with images in the scenes array and the background() is set accordingly. A separate button class is required and code for this follows the demo.
color BLUE = color(64, 124, 188);
color LTGRAY = color(185, 180, 180);
color YELLOW = color(245, 250, 13);
color RED = color(255, 0, 0);
color BLACK = color(0, 0, 0);
color WHITE = color(255, 255, 255);
color GREEN = color(0, 255, 0);
color ORANGE = color(247, 168, 7);
PFont font;
PImage[] scenes = new PImage[6];
// **** Up/Down Buttons init, min, max values **** //
final int _initValue = 2;
final int _maxValue = 5;
final int _minValue = 0;
int stepperValue = 0;
Button _up;
Button _dwn;
Button _quit;
final int _displayX = 160;
final int _displayY = 30;
final int _displayW = 100;
final int _displayH = 24;
final int _txtSize = 18;
void stepperValueDisplay(int value) {
fill(WHITE); // background color
noStroke();
rect(_displayX, _displayY, _displayW, _displayH, 0);
fill(BLACK); // text color
textSize(_txtSize);
textAlign(CENTER);
String str = String.format("Scene %d", value);
text(str, _displayX, _displayY, _displayW, _displayH);
}
void scene_0(){
background(RED);
save("scene0.png");
}
void scene_1(){
background(GREEN);
save("scene1.png");
}
void scene_2(){
background(BLACK);
save("scene2.png");
}
void scene_3(){
background(YELLOW);
save("scene3.png");
}
void scene_4(){
background(LTGRAY);
save("scene4.png");
}
void scene_5(){
background(ORANGE);
save("scene5.png");
}
void setup() {
size(600, 600);
background(BLUE);
font = createFont("Menlo-Bold", 20);
_dwn = new Button( _displayX - 40, _displayY, 40, 24, "--", LTGRAY, BLACK);
_up = new Button( _displayX + _displayW, _displayY, 40, 24, "++", LTGRAY, BLACK);
stepperValue = _initValue;
_quit = new Button(width - 60, 20, 30, 24, "Q", LTGRAY, BLACK);
scene_0();
scene_1();
scene_2();
scene_3();
scene_4();
scene_5();
scenes[0] = loadImage("scene0.png");
scenes[1] = loadImage("scene1.png");
scenes[2] = loadImage("scene2.png");
scenes[3] = loadImage("scene3.png");
scenes[4] = loadImage("scene4.png");
scenes[5] = loadImage("scene5.png");
}
void draw() {
background(scenes[stepperValue]);
_up.display();
_dwn.display();
_quit.display();
stepperValueDisplay(stepperValue);
}
void mousePressed() {
if (mouseX > _quit.x && mouseX < _quit.x + _quit.w && mouseY > _quit.y && mouseY < _quit.y + _quit.h) {
exit();
}
if (mouseX > _up.x && mouseX < _up.x + _up.w && mouseY > _up.y && mouseY < _up.y + _up.h) {
stepperValue++;
if (stepperValue > _maxValue) {
stepperValue = _maxValue;
}
stepperValueDisplay(stepperValue);
}
if (mouseX > _dwn.x && mouseX < _dwn.x + _dwn.w && mouseY > _dwn.y && mouseY < _dwn.y + _dwn.h) {
stepperValue--;
if (stepperValue < _minValue) {
stepperValue = _minValue;
}
stepperValueDisplay(stepperValue);
}
}
Button Class:
int _btnTxtSize = 18;
class Button {
float x, y, w, h;
String title;
color bkgrndColor;
color txtColor;
// Constructor
Button(int xpos, int ypos, float wt, float ht, String titleStr, color background, color textColor) {
x = xpos;
y = ypos;
w = wt;
h = ht;
title = titleStr;
bkgrndColor = background;
txtColor = textColor;
}
void display(){
fill(bkgrndColor);
noStroke();
rect( x, y, w, h, 0);
fill(txtColor);
textSize(_btnTxtSize);
textAlign(CENTER);
text(title, x, y, w, h);
}
}

I am using following code of Scaling image in monotouch but it is not maintaining quality of image

public static class ImageHelper
{
public static UIImage Scale (UIImage source, SizeF newSize)
{
UIGraphics.BeginImageContext (newSize);
var context = UIGraphics.GetCurrentContext ();
context.InterpolationQuality=CGInterpolationQuality.High;
context.TranslateCTM (0, newSize.Height);
context.ScaleCTM (1f, -1f);
context.DrawImage (new RectangleF (0, 0, newSize.Width, newSize.Height), source.CGImage);
var scaledImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return scaledImage;
}
public static UIImage Rotate (UIImage image)
{
UIImage res;
using (CGImage imageRef = image.CGImage) {
CGImageAlphaInfo alphaInfo = imageRef.AlphaInfo;
CGColorSpace colorSpaceInfo = CGColorSpace.CreateDeviceRGB ();
if (alphaInfo == CGImageAlphaInfo.None) {
alphaInfo = CGImageAlphaInfo.NoneSkipLast;
}
int width, height;
width = imageRef.Width;
height = imageRef.Height;
int maxSize = Math.Max (width, height);
if (height >= width) {
width = (int)Math.Floor ((double)width * ((double)maxSize / (double)height));
height = maxSize;
} else {
height = (int)Math.Floor ((double)height * ((double)maxSize / (double)width));
width = maxSize;
}
CGBitmapContext bitmap;
if (image.Orientation == UIImageOrientation.Up || image.Orientation == UIImageOrientation.Down) {
bitmap = new CGBitmapContext (IntPtr.Zero, width, height, imageRef.BitsPerComponent, imageRef.BytesPerRow, colorSpaceInfo, alphaInfo);
} else {
bitmap = new CGBitmapContext (IntPtr.Zero, height, width, imageRef.BitsPerComponent, imageRef.BytesPerRow, colorSpaceInfo, alphaInfo);
}
switch (image.Orientation) {
case UIImageOrientation.Left:
bitmap.RotateCTM ((float)Math.PI / 2);
bitmap.TranslateCTM (0, -height);
break;
case UIImageOrientation.Right:
bitmap.RotateCTM (-((float)Math.PI / 2));
bitmap.TranslateCTM (-width, 0);
break;
case UIImageOrientation.Up:
break;
case UIImageOrientation.Down:
bitmap.TranslateCTM (width, height);
bitmap.RotateCTM (-(float)Math.PI);
break;
}
bitmap.DrawImage (new Rectangle (0, 0, width, height), imageRef);
res = UIImage.FromImage (bitmap.ToImage ());
bitmap = null;
}
return res;
}
}
Calling method=> UIImage ScaledImage =ImageHelper.Scale (ImageHelper.Rotate (downloadedImage), new SizeF (270, 260));
Please provide any solution to maintain quality as well as it will scale to required size.
Xamarin's UIImage implementation contains two different Scale() methods
Scale(System.Drawing.SizeF) : UIImage
Scale(System.Drawing.SizeF, float) : UIImage

cocos2d box2d scale sprite -> removechild (how?)

I am little slow in English, please do understand.
Here is my source code:
- (void)createBall:(CGPoint)touchedAt{
CGSize winSize = [CCDirector sharedDirector].winSize;
ball2 = [CCSprite spriteWithFile:#"Ball.png" rect:CGRectMake(0, 0, 54, 54)];
ball2.position = ccp(touchedAt.x,touchedAt.y);
[self addChild:ball2];
b2BodyDef ballBodyDef2;
ballBodyDef2.type = b2_dynamicBody;
ballBodyDef2.position.Set(touchedAt.x/PTM_RATIO, touchedAt.y/PTM_RATIO);
ballBodyDef2.userData = ball2;
b2Body *body2 = _world->CreateBody(&ballBodyDef2);
b2CircleShape circle;
circle.m_radius = 89.0/PTM_RATIO;//(arc4random()*26.0)/PTM_RATIO;
b2FixtureDef ballShapeDef2;
ballShapeDef2.shape = &circle;
ballShapeDef2.density = 1.0f;
ballShapeDef2.friction = 0.2f;
ballShapeDef2.restitution = 0.8f;
body2->CreateFixture(&ballShapeDef2);
}
-(void)createBall2
{
CGSize winSize = [CCDirector sharedDirector].winSize;
globalSprite = [CCSprite spriteWithFile:#"Ball.png"];
globalSprite.position = ccp(winSize.width/2 + globalSprite.contentSize.width, winSize.height/2);
[self addChild:globalSprite];
b2BodyDef ballBodyDef3;
ballBodyDef3.type = b2_dynamicBody;
ballBodyDef3.position.Set(100/PTM_RATIO, 100/PTM_RATIO);
ballBodyDef3.userData = globalSprite ;
b2Body *body3 = _world->CreateBody(&ballBodyDef3);
b2CircleShape circle;
circle.m_radius = 26.0/PTM_RATIO;//(arc4random()*26.0)/PTM_RATIO;
b2FixtureDef ballShapeDef3;
ballShapeDef3.shape = &circle;
ballShapeDef3.density = 1.0f;
ballShapeDef3.friction = 0.2f;
ballShapeDef3.restitution = 0.8f;
body3->CreateFixture(&ballShapeDef3);
}
// initialize your instance here
-(id) init
{
if( (self=[super init])) {
// enable touch
// enable accelerometer
CGSize winSize = [CCDirector sharedDirector].winSize;
self.isAccelerometerEnabled = YES;
self.isTouchEnabled = YES;
// Create sprite and add it to the layer
// Create a world
b2Vec2 gravity = b2Vec2(0.0f, 0.0f);
bool doSleep = true;
_world = new b2World(gravity, doSleep);
// Create edges around the entire screen
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0,0);
b2Body *groundBody = _world->CreateBody(&groundBodyDef);
b2PolygonShape groundBox;
b2FixtureDef boxShapeDef;
boxShapeDef.shape = &groundBox;
groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(winSize.width/PTM_RATIO, 0));
groundBody->CreateFixture(&boxShapeDef);
groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(0, winSize.height/PTM_RATIO));
groundBody->CreateFixture(&boxShapeDef);
groundBox.SetAsEdge(b2Vec2(0, winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO));
groundBody->CreateFixture(&boxShapeDef);
groundBox.SetAsEdge(b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO, 0));
groundBody->CreateFixture(&boxShapeDef);
// Create ball body and shape
[self schedule:#selector(tick:)];
//[self schedule:#selector(gameLogic:) interval:1.0];
[self createBall2];
}
return self;
}
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
// Choose one of the touches to work with
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
[self createBall:location];
}
- (void)tick:(ccTime) dt {
_world->Step(dt, 10, 10);
for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *ballData = (CCSprite *)b->GetUserData();
ballData.position = ccp(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO);
ballData.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
}
I want to
touch -> sprite create(circle) -> sprite scale -> sprite remove
but
- (void)tick:(ccTime) dt <---------- this is simulator turn off!
I want to way
Try this :
world->DestroyBody(sprite);

App using MonoTouch Core Graphics mysteriously crashes

My app launches with a view controller and a simple view consisting of a button and a subview. When the user touches the button, the subview is populated with scrollviews that display the column headers, row headers, and cells of a spreadsheet. To draw the cells, I use CGBitmapContext to draw the cells, generate an image, and then put the image into the imageview contained in the scrollview that displays the cells.
When I run the app on the iPad, it displays the cells just fine, and the scrollview lets the user scroll around in the spreadsheet without any problems. If the user touches the button a second time, the spreadsheet redraws and continues to work perfectly, If, however, the user touches the button a third time, the app crashes. There is no exception information display in the Application Output window.
My first thought was that the successive button pushes were using up all the available memory, so I overrode the DidReceiveMemoryWarning method in the view controller and used a breakpoint to confirm that this method was not getting called. My next thought was that the CGBitmapContext was not getting released and looked for a Monotouch equivalent of Objective C's CGContextRelease() function. The closest I could find was the CGBitmapContext instance method Dispose(), which I called, without solving the problem.
In order to free up as much memory as possible (in case I was somehow running out of memory without tripping a warning), I tried forcing garbage collection each time I finished using a CGBitmapContext. This made the problem worse. Now the program would crash moments after displaying the spreadsheet the first time. This caused me to wonder whether the Garbage Collector was somehow collecting something necessary to the continued display of graphics on the screen.
I would be grateful for any suggestions on further avenues to investigate for the cause of these crashes. I have included the source code for the SpreadsheetView class. The relevant method is DrawSpreadsheet(), which is called when the button is touched.
Thank you for your assistance on this matter.
Stephen Ashley
public class SpreadsheetView : UIView
{
public ISpreadsheetMessenger spreadsheetMessenger = null;
public UIScrollView cellsScrollView = null;
public UIImageView cellsImageView = null;
public SpreadsheetView(RectangleF frame) : base()
{
Frame = frame;
BackgroundColor = Constants.backgroundBlack;
AutosizesSubviews = true;
}
public void DrawSpreadsheet()
{
UInt16 RowHeaderWidth = spreadsheetMessenger.RowHeaderWidth;
UInt16 RowHeaderHeight = spreadsheetMessenger.RowHeaderHeight;
UInt16 RowCount = spreadsheetMessenger.RowCount;
UInt16 ColumnHeaderWidth = spreadsheetMessenger.ColumnHeaderWidth;
UInt16 ColumnHeaderHeight = spreadsheetMessenger.ColumnHeaderHeight;
UInt16 ColumnCount = spreadsheetMessenger.ColumnCount;
// Add the corner
UIImageView cornerView = new UIImageView(new RectangleF(0f, 0f,
RowHeaderWidth, ColumnHeaderHeight));
cornerView.BackgroundColor = Constants.headingColor;
CGColorSpace cornerColorSpace = null;
CGBitmapContext cornerContext = null;
IntPtr buffer = Marshal.AllocHGlobal(RowHeaderWidth * ColumnHeaderHeight * 4);
if (buffer == IntPtr.Zero)
throw new OutOfMemoryException("Out of memory.");
try
{
cornerColorSpace = CGColorSpace.CreateDeviceRGB();
cornerContext = new CGBitmapContext
(buffer, RowHeaderWidth, ColumnHeaderHeight, 8, 4 * RowHeaderWidth,
cornerColorSpace, CGImageAlphaInfo.PremultipliedFirst);
cornerContext.SetFillColorWithColor(Constants.headingColor.CGColor);
cornerContext.FillRect(new RectangleF(0f, 0f, RowHeaderWidth, ColumnHeaderHeight));
cornerView.Image = UIImage.FromImage(cornerContext.ToImage());
}
finally
{
Marshal.FreeHGlobal(buffer);
if (cornerContext != null)
{
cornerContext.Dispose();
cornerContext = null;
}
if (cornerColorSpace != null)
{
cornerColorSpace.Dispose();
cornerColorSpace = null;
}
}
cornerView.Image = DrawBottomRightCorner(cornerView.Image);
AddSubview(cornerView);
// Add the cellsScrollView
cellsScrollView = new UIScrollView
(new RectangleF(RowHeaderWidth, ColumnHeaderHeight,
Frame.Width - RowHeaderWidth,
Frame.Height - ColumnHeaderHeight));
cellsScrollView.ContentSize = new SizeF
(ColumnCount * ColumnHeaderWidth,
RowCount * RowHeaderHeight);
Size iContentSize = new Size((int)cellsScrollView.ContentSize.Width,
(int)cellsScrollView.ContentSize.Height);
cellsScrollView.BackgroundColor = UIColor.Black;
AddSubview(cellsScrollView);
CGColorSpace colorSpace = null;
CGBitmapContext context = null;
CGGradient gradient = null;
UIImage image = null;
int bytesPerRow = 4 * iContentSize.Width;
int byteCount = bytesPerRow * iContentSize.Height;
buffer = Marshal.AllocHGlobal(byteCount);
if (buffer == IntPtr.Zero)
throw new OutOfMemoryException("Out of memory.");
try
{
colorSpace = CGColorSpace.CreateDeviceRGB();
context = new CGBitmapContext
(buffer, iContentSize.Width,
iContentSize.Height, 8, 4 * iContentSize.Width,
colorSpace, CGImageAlphaInfo.PremultipliedFirst);
float[] components = new float[]
{.75f, .75f, .75f, 1f,
.25f, .25f, .25f, 1f};
float[] locations = new float[]{0f, 1f};
gradient = new CGGradient(colorSpace, components, locations);
PointF startPoint = new PointF(0f, (float)iContentSize.Height);
PointF endPoint = new PointF((float)iContentSize.Width, 0f);
context.DrawLinearGradient(gradient, startPoint, endPoint, 0);
context.SetLineWidth(Constants.lineWidth);
context.BeginPath();
for (UInt16 i = 1; i <= RowCount; i++)
{
context.MoveTo
(0f, iContentSize.Height - i * RowHeaderHeight + (Constants.lineWidth/2));
context.AddLineToPoint((float)iContentSize.Width,
iContentSize.Height - i * RowHeaderHeight + (Constants.lineWidth/2));
}
for (UInt16 j = 1; j <= ColumnCount; j++)
{
context.MoveTo((float)j * ColumnHeaderWidth - Constants.lineWidth/2,
(float)iContentSize.Height);
context.AddLineToPoint((float)j * ColumnHeaderWidth - Constants.lineWidth/2, 0f);
}
context.StrokePath();
image = UIImage.FromImage(context.ToImage());
}
finally
{
Marshal.FreeHGlobal(buffer);
if (gradient != null)
{
gradient.Dispose();
gradient = null;
}
if (context != null)
{
context.Dispose();
context = null;
}
if (colorSpace != null)
{
colorSpace.Dispose();
colorSpace = null;
}
// GC.Collect();
//GC.WaitForPendingFinalizers();
}
UIImage finalImage = ActivateCell(1, 1, image);
finalImage = ActivateCell(0, 0, finalImage);
cellsImageView = new UIImageView(finalImage);
cellsImageView.Frame = new RectangleF(0f, 0f,
iContentSize.Width, iContentSize.Height);
cellsScrollView.AddSubview(cellsImageView);
}
private UIImage ActivateCell(UInt16 column, UInt16 row, UIImage backgroundImage)
{
UInt16 ColumnHeaderWidth = (UInt16)spreadsheetMessenger.ColumnHeaderWidth;
UInt16 RowHeaderHeight = (UInt16)spreadsheetMessenger.RowHeaderHeight;
CGColorSpace cellColorSpace = null;
CGBitmapContext cellContext = null;
UIImage cellImage = null;
IntPtr buffer = Marshal.AllocHGlobal(4 * ColumnHeaderWidth * RowHeaderHeight);
if (buffer == IntPtr.Zero)
throw new OutOfMemoryException("Out of memory: ActivateCell()");
try
{
cellColorSpace = CGColorSpace.CreateDeviceRGB();
// Create a bitmap the size of a cell
cellContext = new CGBitmapContext
(buffer, ColumnHeaderWidth, RowHeaderHeight, 8,
4 * ColumnHeaderWidth, cellColorSpace, CGImageAlphaInfo.PremultipliedFirst);
// Paint it white
cellContext.SetFillColorWithColor(UIColor.White.CGColor);
cellContext.FillRect(new RectangleF(0f, 0f, ColumnHeaderWidth, RowHeaderHeight));
// Convert it to an image
cellImage = UIImage.FromImage(cellContext.ToImage());
}
finally
{
Marshal.FreeHGlobal(buffer);
if (cellContext != null)
{
cellContext.Dispose();
cellContext = null;
}
if (cellColorSpace != null)
{
cellColorSpace.Dispose();
cellColorSpace = null;
}
// GC.Collect();
//GC.WaitForPendingFinalizers();
}
// Draw the border on the cell image
cellImage = DrawBottomRightCorner(cellImage);
CGColorSpace colorSpace = null;
CGBitmapContext context = null;
Size iContentSize = new Size((int)backgroundImage.Size.Width,
(int)backgroundImage.Size.Height);
buffer = Marshal.AllocHGlobal(4 * iContentSize.Width * iContentSize.Height);
if (buffer == IntPtr.Zero)
throw new OutOfMemoryException("Out of memory: ActivateCell().");
try
{
colorSpace = CGColorSpace.CreateDeviceRGB();
// Set up a bitmap context the size of the whole grid
context = new CGBitmapContext
(buffer, iContentSize.Width,
iContentSize.Height, 8, 4 * iContentSize.Width,
colorSpace, CGImageAlphaInfo.PremultipliedFirst);
// Draw the original grid into the bitmap
context.DrawImage(new RectangleF(0f, 0f, iContentSize.Width, iContentSize.Height),
backgroundImage.CGImage);
// Draw the cell image into the bitmap
context.DrawImage(new RectangleF(column * ColumnHeaderWidth,
iContentSize.Height - (row + 1) * RowHeaderHeight,
ColumnHeaderWidth, RowHeaderHeight),
cellImage.CGImage);
// Convert the bitmap back to an image
backgroundImage = UIImage.FromImage(context.ToImage());
}
finally
{
Marshal.FreeHGlobal(buffer);
if (context != null)
{
context.Dispose();
context = null;
}
if (colorSpace != null)
{
colorSpace.Dispose();
colorSpace = null;
}
// GC.Collect();
//GC.WaitForPendingFinalizers();
}
return backgroundImage;
}
private UIImage DrawBottomRightCorner(UIImage image)
{
int width = (int)image.Size.Width;
int height = (int)image.Size.Height;
float lineWidth = Constants.lineWidth;
CGColorSpace colorSpace = null;
CGBitmapContext context = null;
UIImage returnImage = null;
IntPtr buffer = Marshal.AllocHGlobal(4 * width * height);
if (buffer == IntPtr.Zero)
throw new OutOfMemoryException("Out of memory: DrawBottomRightCorner().");
try
{
colorSpace = CGColorSpace.CreateDeviceRGB();
context = new CGBitmapContext
(buffer, width, height, 8, 4 * width, colorSpace,
CGImageAlphaInfo.PremultipliedFirst);
context.DrawImage(new RectangleF(0f, 0f, width, height),
image.CGImage);
context.BeginPath();
context.MoveTo(0f, (int)(lineWidth/2f));
context.AddLineToPoint(width - (int)(lineWidth/2f), (int)(lineWidth/2f));
context.AddLineToPoint(width - (int)(lineWidth/2f), height);
context.SetLineWidth(Constants.lineWidth);
context.SetStrokeColorWithColor(UIColor.Black.CGColor);
context.StrokePath();
returnImage = UIImage.FromImage(context.ToImage());
}
finally
{
Marshal.FreeHGlobal(buffer);
if (context != null){
context.Dispose();
context = null;}
if (colorSpace != null){
colorSpace.Dispose();
colorSpace = null;}
// GC.Collect();
//GC.WaitForPendingFinalizers();
}
return returnImage;
}
}
Not sure if this will solve your problem (I'm even newer to this than you are), but it seems from this answer that MonoTouch prefers a different paradigm for creating/releasing graphics contexts, along the lines of:
UIGraphics.BeginImageContext(rect.Size)
var context = UIContext.GetCurrentContext();
// ... do stuff ...
UIImage image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
// ... do something with image ...
I don't know if it's releasing everything properly, but otherwise it seems to work.

Resources