I have a little cocos2d-x v3 Windows project and I want an animated sprite. The sprite I have in an object named Worker with other parameters. To run the animation I tried the following, but it always gives a segmentation fault:
//worker.cpp:
...
void Worker::initAnimationWalk() {
spritebatch = cocos2d::SpriteBatchNode::create("robo.png");
auto cache = cocos2d::SpriteFrameCache::getInstance();
cache->addSpriteFramesWithFile("robo.plist");
worker = cocos2d::Sprite::createWithSpriteFrameName("robot1.png");
//spritebatch->addChild(worker);
Vector<SpriteFrame *> animFrames(3);
char str[100] = {0};
for(int i = 1; i <= 3; i++)
{
sprintf(str, "robot%i.png", i);
cocos2d::SpriteFrame* frame = cache->getSpriteFrameByName( str );
animFrames.pushBack(frame);
}
animation = cocos2d::Animation::createWithSpriteFrames(animFrames, 0.2f);
}
cocos2d::Animation *Worker::getAnimationWalk() {
return animation;
}
...
//Worker.h
#ifndef __WORKER_H__
#define __WORKER_H__
#include "cocos2d.h"
class Worker
{
public:
...
void initAnimationWalk();
cocos2d::Animation *getAnimationWalk();
private:
cocos2d::Animation *animation;
cocos2d::Sprite *worker;
cocos2d::SpriteBatchNode *spritebatch;
};
#endif
//Now i want the animation in my scene:
//HellowWorldScene.cpp
void HelloWorld::setMyAction() { //all Worker Objects in an vector
vector<Worker>::iterator it = workerVector.begin();
for(int i = 0; i<workerVector.size();i++) {
it->getWorker()->stopAllActions();
auto actionAnim = Animate::create(it->getAnimationWalk());
if(it->getWorker()->getPosition().x > 0.50*2*p.x) {
auto action = cocos2d::MoveTo::create(it->getSpeed(),Point(0,it->getWorker()->getPosition().y));
auto sp = Spawn::createWithTwoActions(action, actionAnim);
it->getWorker()->runAction(sp);
it->getWorker()->setFlipX(true);
} else {
auto action = cocos2d::MoveTo::create(it->getSpeed(),Point(2*p.x,it->getWorker()->getPosition().y));
auto sp = Spawn::createWithTwoActions(action, actionAnim);
it->getWorker()->runAction(sp);
it->getWorker()->setFlipX(false);
}
}
it++
}
Any help?
SpriteAnimation auto change images using Animation.
Animation *animation2=Animation::create();
animation2->setDelayPerUnit(0.7f);//Time Duration change Images
animation2->addSpriteFrameWithFile("img_1.png");
animation2->addSpriteFrameWithFile("img_2.png");
animation2->addSpriteFrameWithFile("img_3.png");
AnimationCache::getInstance()->addAnimation(animation2, "animation2");
SpriteName->runAction(Sequence::create(Animate::create(animation2),NULL));//this animation Only One time
OR
SpriteName->runAction(RepeatForever::create(Sequence::create(Animate::create(animation2),NULL)));//If Repeate this animation write it..
SpriteAnimation auto change images using Animation.
Animation *anim=Animation::create();
anim->setDelayPerUnit(0.7f);//Time Duration change Images
anim->addSpriteFrameWithFile("img_01.png");
anim->addSpriteFrameWithFile("img_02.png");
anim->addSpriteFrameWithFile("img_03.png");
AnimationCache::getInstance()->addAnimation(anim, "anim");
SpriteNM->runAction(Sequence::create(Animate::create(anim),NULL));//this animation Only One time
OR
SpriteNM->runAction(RepeatForever::create(Sequence::create(Animate::create(anim),NULL)));//If Repeate this animation write it..
Related
I have a quite simple unity GUI that has the following scheme :
Where Brekt and so are buttons.
The GUI works just fine on PC and is on screen space : overlay so it is supposed to be adapted automatically to fit every screen.
But on tablet the whole GUI is smaller and reduced in the center of the screen, with huge margins around the elements (can't join a screenshot now)
What is the way to fix that? Is it something in player settings or in project settings?
Automatically scaling the UI requires using combination of anchor,pivot point of RecTransform and the Canvas Scaler component. It is hard to understand it without images or videos. It is very important that you thoroughly understand how to do this and Unity provided full video tutorial for this.You can watch it here.
Also, when using scrollbar, scrollview and other similar UI controls, the ContentSizeFitter component is also used to make sure they fit in that layout.
There is a problem with MovementRange. We must scale this value too.
I did it so:
public int MovementRange = 100;
public AxisOption axesToUse = AxisOption.Both; // The options for the axes that the still will use
public string horizontalAxisName = "Horizontal"; // The name given to the horizontal axis for the cross platform input
public string verticalAxisName = "Vertical"; // The name given to the vertical axis for the cross platform input
private int _MovementRange = 100;
Vector3 m_StartPos;
bool m_UseX; // Toggle for using the x axis
bool m_UseY; // Toggle for using the Y axis
CrossPlatformInputManager.VirtualAxis m_HorizontalVirtualAxis; // Reference to the joystick in the cross platform input
CrossPlatformInputManager.VirtualAxis m_VerticalVirtualAxis; // Reference to the joystick in the cross platform input
void OnEnable()
{
CreateVirtualAxes();
}
void Start()
{
m_StartPos = transform.position;
Canvas c = GetComponentInParent<Canvas>();
_MovementRange = (int)(MovementRange * c.scaleFactor);
Debug.Log("Range:"+ _MovementRange);
}
void UpdateVirtualAxes(Vector3 value)
{
var delta = m_StartPos - value;
delta.y = -delta.y;
delta /= _MovementRange;
if (m_UseX)
{
m_HorizontalVirtualAxis.Update(-delta.x);
}
if (m_UseY)
{
m_VerticalVirtualAxis.Update(delta.y);
}
}
void CreateVirtualAxes()
{
// set axes to use
m_UseX = (axesToUse == AxisOption.Both || axesToUse == AxisOption.OnlyHorizontal);
m_UseY = (axesToUse == AxisOption.Both || axesToUse == AxisOption.OnlyVertical);
// create new axes based on axes to use
if (m_UseX)
{
m_HorizontalVirtualAxis = new CrossPlatformInputManager.VirtualAxis(horizontalAxisName);
CrossPlatformInputManager.RegisterVirtualAxis(m_HorizontalVirtualAxis);
}
if (m_UseY)
{
m_VerticalVirtualAxis = new CrossPlatformInputManager.VirtualAxis(verticalAxisName);
CrossPlatformInputManager.RegisterVirtualAxis(m_VerticalVirtualAxis);
}
}
public void OnDrag(PointerEventData data)
{
Vector3 newPos = Vector3.zero;
if (m_UseX)
{
int delta = (int)(data.position.x - m_StartPos.x);
delta = Mathf.Clamp(delta, -_MovementRange, _MovementRange);
newPos.x = delta;
}
if (m_UseY)
{
int delta = (int)(data.position.y - m_StartPos.y);
delta = Mathf.Clamp(delta, -_MovementRange, _MovementRange);
newPos.y = delta;
}
transform.position = new Vector3(m_StartPos.x + newPos.x, m_StartPos.y + newPos.y, m_StartPos.z + newPos.z);
UpdateVirtualAxes(transform.position);
}
I'm testing manual animation. However, the animation seems to have some issues, so it doesn't work.
These are the code. Can you take a look and let me where I'm wrong.
HelloWorldScene.h
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
#include <string>
USING_NS_CC;
class HelloWorld : public cocos2d::CCLayerColor{
public:
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::CCScene* scene();
// a selector callback
void menuCloseCallback(CCObject* pSender);
// implement the "static node()" method manually
CREATE_FUNC(HelloWorld);
virtual void onEnter();
protected:
CCSprite* m_grossini;
};
#endif // __HELLOWORLD_SCENE_H__
HelloWorldScene.cpp
#include "HelloWorldScene.h"
USING_NS_CC;
CCScene* HelloWorld::scene()
{
CCScene *scene = CCScene::create();
HelloWorld *layer = HelloWorld::create();
scene->addChild(layer);
return scene;
}
bool HelloWorld::init()
{
if ( !CCLayerColor::initWithColor( ccc4(255,255,255,255) ) )
{
return false;
}
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
this,
menu_selector(HelloWorld::menuCloseCallback));
pCloseItem->setPosition(ccp(origin.x + visibleSize.width - pCloseItem->getContentSize().width/2 ,
origin.y + pCloseItem->getContentSize().height/2));
CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
pMenu->setPosition(CCPointZero);
this->addChild(pMenu, 1);
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
m_grossini = CCSprite::create("grossini.png");
m_grossini->retain();
this->addChild(m_grossini);
m_grossini->setPosition(ccp(winSize.width/2, winSize.height/2));
return true;
}
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
#else
CCDirector::sharedDirector()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
#endif
}
void HelloWorld::onEnter(){
CCAnimation* animation = CCAnimation::create();
for( int i=1;i<15;i++)
{
char szName[100] = {0};
sprintf(szName, "grossini_dance_%02d.png", i);
animation->addSpriteFrameWithFileName(szName);
}
// should last 2.8 seconds. And there are 14 frames.
animation->setDelayPerUnit(2.8f / 14.0f);
animation->setRestoreOriginalFrame(true);
CCAnimate* action = CCAnimate::create(animation);
m_grossini->runAction(CCSequence::create(action, action->reverse(), NULL));
}
I hope you can help me. Thank you so much!
Try following things:..
First of all remove this line m_grossini->retain(); because addchild automatically increase its retain count.
Found the problem..
As you are overriding the OnEnter method you need to call it manually for the base class. In your case adding the line:-
CCLayerColor::onEnter();
in the OnEnter method will do the work.
In future be careful while overriding base class methods.
try this code:
CCAnimation* animation = CCAnimation::create();
for( int i=1;i<15;i++)
animation->addSpriteFrameWithFileName((CCString::createWithFormat("grossini_dance_%02d.png",i)->getCString()));
// should last 2.8 seconds. And there are 14 frames.
animation->setDelayPerUnit(2.8f / 14.0f);
animation->setRestoreOriginalFrame(true);
CCAnimate* action = CCAnimate::create(animation);
m_grossini->runAction(action); //Run once all frame(OR)
m_grossini->runAction(CCRepeatForever::create(action)); //Run RepeatForever
I have written code for a game in which some birds are flying. I created array of CCSprite and added them on Scene. Now it assign a scheduler to each bird object for moving in random direction in screen. All are working. Now i am getting trouble in getting collision in birds.
i am trying to run a CCARRAY_FOREACH loop on array but its giving error.
0xC0000005: Access violation reading location 0xfeeefeee.
Please help me how i can get get collision detection in array element while they are moving. updateCollison method is not executing.
My Code is:
#include "HelloWorldScene.h"
using namespace cocos2d;
CCScene* HelloWorld::scene()
{
CCScene * scene = NULL;
do
{
// 'scene' is an autorelease object
scene = CCScene::create();
CC_BREAK_IF(! scene);
// 'layer' is an autorelease object
HelloWorld *layer = HelloWorld::create();
CC_BREAK_IF(! layer);
// add layer as a child to scene
scene->addChild(layer);
} while (0);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//srand(time(NULL));
CCSize size = CCDirector::sharedDirector()->getWinSize();
birds = CCArray::create();
for(int j = 0; j<5; j++){
CCSprite *bird = CCSprite::create("twitter_square.png");
bird->setTag(j);
int max = rand() % 480;
int min = rand() % 320;
bird->setPosition(ccp(max, min));
this->addChild(bird);
birds->addObject(bird);
bird->schedule( schedule_selector(HelloWorld::moveBird), 5.0 );
bird->schedule( schedule_selector(HelloWorld::updateCollison), 5.0 );
}
return true;
}
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
CCDirector::sharedDirector()->end();
}
void HelloWorld::moveBird(float dt)
{
CCSize size = CCDirector::sharedDirector()->getWinSize();
int max = rand() % (int)size.width;
int min = rand() % (int)size.height;
CCActionInterval* actionTo = CCMoveTo::actionWithDuration(5, ccp(max,min));
this->runAction(actionTo);
}
void HelloWorld::updateCollison(float dt)
{
CCObject *obj;
for(int i=0; i < birds->count(); i++)
{
CCLOG("$$$$$$$$$$$$$$$$$$$$$$$");
}
}
It's better to do things in one update function ...for example make one update in that call MoveBird Function which will contain your moving bird code
Secondly now call check Collision function
void update (float dt) {
MoveBird(); // Move how many birds you want to move
CheckCollision();
}
Now how to check collision of your birds
In your collision function forLoop your birds Array check
if(mBirdsArray[i]->boundingBox().containsPoint(mBirdsArray[j]->getPosition()))
and vice versa ...
I hope this will work .. .there maybe better logic than this ..
I'm trying to handle the program window being resized, and the (I think inefficient) code I've flung together below seems to do the trick.
Is there a better way to do this, preferably one that does not create a stutter when resizing the window and which does not constantly use 12-17% of a CPU? I also suspect MessagePump.Run may somehow run before form.Resize finishes setting up the device again, and throw an error.
Thanks!
using System;
using System.Drawing;
using System.Windows.Forms;
using SlimDX;
using SlimDX.Direct3D9;
using SlimDX.Windows;
namespace SlimDX_1
{
struct Vertex
{
public Vector4 Position;
public int Color;
}
static class Program
{
private static VertexBuffer vertices;
private static Device device;
private static RenderForm form;
private static PresentParameters present;
private static VertexDeclaration vertexDecl;
private static VertexElement[] vertexElems;
private static bool wasMinimized = false;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
form = new RenderForm("Tutorial 1: Basic Window");
init();
form.Resize += (o, e) =>
{
if (form.WindowState == FormWindowState.Minimized)
{
foreach (var item in ObjectTable.Objects)
{
item.Dispose();
}
wasMinimized = true;
}
else
{
foreach (var item in ObjectTable.Objects)
{
item.Dispose();
}
init();
device.SetRenderState(RenderState.FillMode, FillMode.Wireframe);
device.SetRenderState(RenderState.CullMode, Cull.None);
present.BackBufferHeight = form.ClientSize.Height;
present.BackBufferWidth = form.ClientSize.Width;
device.Reset(present);
}
};
MessagePump.Run(form, () =>
{
if (form.WindowState == FormWindowState.Minimized)
{
return;
}
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0);
device.BeginScene();
device.SetStreamSource(0, vertices, 0, 20); // 20 is the size of each vertex
device.VertexDeclaration = vertexDecl;
device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
device.EndScene();
device.Present();
});
foreach (var item in ObjectTable.Objects)
{
item.Dispose();
}
}
private static void init()
{
present = new PresentParameters();
//present.EnableAutoDepthStencil = false;
//present.BackBufferCount = 1;
//present.SwapEffect = SwapEffect.Discard;
present.Windowed = true;
present.BackBufferHeight = form.ClientSize.Height;
present.BackBufferWidth = form.ClientSize.Width;
//present.BackBufferFormat = Format.Unknown;
device = new Device(new Direct3D(), 0, DeviceType.Hardware, form.Handle, CreateFlags.HardwareVertexProcessing, present);
vertices = new VertexBuffer(device, 3 * 20, Usage.WriteOnly, VertexFormat.None, Pool.Managed);
vertices.Lock(0, 0, LockFlags.None).WriteRange(new Vertex[]
{
new Vertex() { Color = Color.Red.ToArgb(), Position = new Vector4(400.0f, 100.0f, 0.5f, 1.0f) },
new Vertex() { Color = Color.Blue.ToArgb(), Position = new Vector4(650.0f, 500.0f, 0.5f, 1.0f) },
new Vertex() { Color = Color.Green.ToArgb(), Position = new Vector4(150.0f, 500.0f, 0.5f, 1.0f) }
});
vertices.Unlock();
// specifies the layout of the vertexes
vertexElems = new VertexElement[]
{
new VertexElement(0, 0, DeclarationType.Float4, DeclarationMethod.Default, DeclarationUsage.PositionTransformed, 0),
new VertexElement(0, 16, DeclarationType.Color, DeclarationMethod.Default, DeclarationUsage.Color, 0),
VertexElement.VertexDeclarationEnd
};
vertexDecl = new VertexDeclaration(device, vertexElems);
}
}
}
You're going way above and beyond what you need to do when the window is resized. You're releasing every single DirectX object you've created, including the graphics device, and then recreating everything. This is going to take a comparatively long time, which is why you're seeing performance issues.
In fact, none of your objects need to be released. Simply call the Reset() function on the device to recreate the backbuffer to match the new window size. Check out some of the native Direct3D9 tutorials on window resizing to see how in general how the process works.
Just make any animation and try to use my code on it. What i'm trying to achieve is to play animation using PlayQueued multiple times, each time with different animation state for example to reverse the animation.
using UnityEngine;
using System.Collections;
public class NewBehaviourScript : MonoBehaviour {
Animation a;
void Start () {
a = animation;
Invoke("PlayAnimation3",0.3f);
}
void PlayAnimation0(){
//no problem at all...
a.PlayQueued("simpleAnimation");
a.PlayQueued("simpleAnimation");
a.PlayQueued("simpleAnimation");
}
void PlayAnimation1(){
//but when you change AnimationState...
a.PlayQueued("simpleAnimation");
AnimationState as0 = a.PlayQueued("simpleAnimation");
as0.time = as0.length;
as0.speed = -1f;
AnimationState as1 = a.PlayQueued("simpleAnimation");
//... the last AnimationState is the one that counts
as1.time = 0f;
as1.speed = 1f;
}
void PlayAnimation2(){
//making a copy of animation does not help
a.PlayQueued("simpleAnimation");
AnimationState as0 = a.PlayQueued("simpleAnimation");
as0.time = as0.length;
as0.speed = -1f;
AnimationState as1 = a.PlayQueued("simpleAnimationCopy");
as1.time = 0f;
as1.speed = 1f;
}
void PlayAnimation3(){
//it seems duplicated animations have common AnimationState...
a["simpleAnimationCopy"].time =a["simpleAnimationCopy"].length;
a["simpleAnimationCopy"].speed =-1f;
a.Play("simpleAnimation");
a.PlayQueued("simpleAnimationCopy");
a.PlayQueued("simpleAnimation");
}
void PlayAnimation4(){
//any ideas? how to use PlayQueued with different animation states?
}
}