cocos2d-x 3.6 PhysicsJointFixed error - cocos2d-x

I am new to cococs2dx and I am working on a code involving PhysicsJointFixed. I am using cocos2d-x-3.6. I am unable to compile the code as I wrote below following the guidelines and the PhysicsTest.cpp.
My GameLayer.h looks like:
class GameLayer : public cocos2d::Layer
{
GameLayer();
virtual ~GameLayer();
virtual bool init();
static Scene* createScene();
void setPhyWorld(PhysicsWorld* world){m_world = world;}
CREATE_FUNC(GameLayer);
private:
PhysicsWorld* m_world;
ShapeSprite* _square; //ShapeSprite extends Sprite
ShapeSprite* _square1;
PhysicsJointFixed* joint;
...
}
The createScene method in GameLayer.cpp:
Scene* GameLayer::createScene()
{
auto scene = Scene::createWithPhysics();
auto layer = GameLayer::create();
layer->setPhyWorld(scene->getPhysicsWorld());
scene->addChild(layer);
return scene;
}
Then inside GameLayer::init()
bool GameLayer::init()
{
if ( !Layer::init() )
{
return false;
}
...
...
_square = ShapeSprite::gameSpriteWithFile("square.png");
auto squareBody = PhysicsBody::createBox(Size(200,200));
_square->setPhysicsBody(squareBody);
_square->setPosition(Vec2(_screenSize.width * 0.5f, _screenSize.height * 0.7f));
_square1 = ShapeSprite::gameSpriteWithFile("square1.png");
auto squareBody1 = PhysicsBody::createBox(Size(100,100));
_square1->setPhysicsBody(squareBody1);
_square1->setPosition(Vec2(_screenSize.width * 0.5f, _screenSize.height * 0.7f));
this->addChild(_square);
this->addChild(_square1);
joint = PhysicsJointFixed::construct(_square->getPhysicsBody(), _square1->getPhysicsBody(),Vec2(100,100));
this->getScene()->getPhysicsWorld()->addJoint(joint);
return true;
}
The code gives EXC_BAD_ACCESS error on the line
this->getScene()->getPhysicsWorld()->addJoint(joint);
because, this->getScene()->getPhysicsWorld() returns NULL.
Please advise, how can I avoid the error. Any suggestion is appreciated. Thanks in advance.

This error occurs because your custom layer is not yet added to scene during init(). One possible solution is to override onEnterTransitionDidFinish() and add the joint there. In GameLayer.h add this:
virtual void onEnterTransitionDidFinish();
And move the joint adding code to GameLayer.cpp like this:
void GameLayer::onEnterTransitionDidFinish() {
joint = PhysicsJointFixed::construct(_square->getPhysicsBody(), _square1->getPhysicsBody(),Vec2(100,100));
this->getScene()->getPhysicsWorld()->addJoint(joint);
}

Related

Functions not doing anything

I have a gameObject called BounceBack that is supposed to bounce the ball back far away when they collide together.
public class BounceBack : MonoBehaviour
{
public GameObject Player;
public float force;
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag(Player.tag))
{
Player.GetComponent<PlayerController>().ForceBack(force);
}
}
}
The ball Player (ball) script:
public class PlayerController : MonoBehaviour
{
public int acceleration;
public int speedLimit;
public int sideSpeed;
public Text countText;
public Text winText;
public GameObject pickUp;
public GameObject finishLine;
//internal void ForceBack() //Not sure what it does and why it's there.
//{
// throw new NotImplementedException();
//}
private int count;
private Rigidbody rb;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
SetCount();
}
// Update is called once per frame
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal") * sideSpeed * rb.velocity.magnitude / acceleration;
//float moveVertical = Input.GetAxis("Vertical") * acceleration;
if (rb.velocity.magnitude <= speedLimit)
{
rb.AddForce(0.0f, 0.0f, acceleration); // add vertical force
}
rb.AddForce(moveHorizontal, 0.0f, 0.0f); // add horizontal force
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag(pickUp.tag))
{
other.GetComponent<Rotate>().Disapear();
count++;
SetCount();
}
if (other.gameObject.CompareTag(finishLine.tag))
{
acceleration = 0;
sideSpeed = 0;
finishLine.GetComponent<GameEnd>().FadeOut();
if (count >= 2)
{
winText.GetComponent<WinTextFadeIn>().FadeIn("Vous avez remporté la partie!");
}
else
{
winText.GetComponent<WinTextFadeIn>().FadeIn("Vous avez perdu. Réesayer?");
}
}
}
private void SetCount()
{
countText.text = "Count : " + count.ToString();
}
public void ForceBack(float force)
{
Rigidbody rb = GetComponent<Rigidbody>();
rb.AddForce(0.0f, 0.0f, -force, ForceMode.VelocityChange);
Debug.Log("Pass");
}
}
The AddForce function does not do anything. I tried with setActive(false) and it's not working either. The only thing that works is Debug.Log(). I'm not sure if the speedlimit and acceleration are interfering with the function.
EDIT: I'm not sure if the problem is from Unity but I can't access any variable of the class from the forceBack function inside the class.
EDIT2: I also tried to call the AddForce function directly in the Bounce Back script but it's not working either.
Player.GetComponent<Rigidbody>().AddForce(0.0f, 0.0f, -force, ForceMode.VelocityChange);
Player (Ball) Screenshot
Bounce Back Screenshot
So, a couple things:
1.) The physics system should already cause the ball to bounce if you've set up the colliders and rigidbodies properly. You should only need to do something like this if the ball should gain momentum when it bounces, which is unlikely. You should post screenshots of their inspectors if this answer doesn't help.
2.) On your rb.AddForce() call, you're applying a force in world-space, which may be the wrong direction to bounce. If you know the ball is oriented the way it's moving, then you can call AddRelativeForce with the same parameters. If the ball's orientation is not controlled, then you need to calculate the correct world-space direction to use before applying the force.
3.) Finally, just to confirm, the objects with BounceBack attached do have a non-zero value in the 'force' parameter in the inspector, right?

Check collision of 2 objects in libgdx

I am making a game in libgdx, where you shoot aliens with bullets. I have 2 ArrayLists of objects and would like to check if any of objects in bulletArrayList is colliding with any object from alienArrayList. What is the best way to do that? I was thinking of contactListener.
In the screen class I am generating objects like this:
public class PlayScreen implements Screen, InputProcessor,ContactListener {
public ArrayList<Alien> alienArrayList = new ArrayList<Alien>();
public ArrayList<Bullet> bulletArrayList = new ArrayList<Bullet>();
public void generateAlien() {
alien = new Alien();
alienArrayList.add(alien);
}
public void shootBullet(float x, float y) {
//send x,y moving coordiantes
bullet = new Bullet(x,y);
bulletArrayList.add(bullet);
}
}
In object class I have Rectangle box which i am moving like this:
public class Alien {
public Alien() {
bound = new Rectangle( x, y, alienRegion.getRegionWidth(), alienRegion.getRegionHeight());
}
public void update(float delta) {
bound.y -= speed * delta;
}
public void render(SpriteBatch batch, float delta) {
update(delta);
elapsedTime += Gdx.graphics.getDeltaTime();
alienRegion = (TextureRegion) alien.getKeyFrame(elapsedTime, true);
batch.draw(alienRegion, getBound().x, getBound().y);
}
}
Because you are using Rectangles in your Alien class, we can use a class called Intersector which has static methods to check for collision detection.
for(Alien alien1: alienArrayList) {
for(Alien alien2 : bulletArrayList) {
if(Intersector.overlaps(alien1.rect, alien2.rect)) {
// Collision code
}
}
}
First, we iterate through the two lists using a nested special for loop. Then we pass two Rectangles to the Intersector.overlaps(rect1, rect2). This is a static method defined in the Intersector class which will return true if the rectangles are overlapping.
Also, this code can go straight into your render method.
This code is not the most optimized because it will check 2 rects twice however, I will leave the optimization to you.
I hope that this answer was helpful and if you have any further questions please feel free to post a comment below.

Libgdx | Custom Action

How can I create a custom action for an actor in libgdx? If I can't, than is there at least an action to run a custom piece of code (eg. call a method action)? Thanks.
EDIT:
I created this class :
class GapSizeAction extends TemporalAction {
private float newSize;
private Blocker blocker;
public static GapSizeAction getRotateAction(float newSize, float duration) {
return new GapSizeAction(newSize, duration);
}
public GapSizeAction(float newSize, float duration) {
super(duration);
System.out.println("Construct");
this.blocker = (Blocker)target;
this.newSize = newSize;
}
private float start, end;
protected void begin() {
System.out.println("Begin");
start = blocker.gap;
}
protected void update(float percent) {
blocker.gap = (start + (end - start) * percent);
}
}
The problem is that I am using a custom actor with a gap member (float). I try to cast the target to a blocker so that I can access the gap member variable, but gap ends up being null. I can confirm that gap is not null, I initialize it in the constructor. The blocker (Custom actor) is not null either. Am I going about this wrong?
Your problem is the line this.blocker = (Blocker)target; in your constructor. When the constructor is called, the action hasn't been set on a target yet, so target is null (and so will be blocker). Also, since you're changing a single float, you can extend FloatAction and save yourself some code. I would write your class as below. The constructor should be empty to support easy pooling, and you can set it up in your static factory method.
class GapSizeAction extends FloatAction {
public static GapSizeAction getRotateAction(float newSize, float duration){
GapSizeAction action = Actions.action(GapSizeAction.class);
action.setEnd(newSize);
action.setDuration(duration);
return action;
}
protected void begin () {
if (target instanceof Blocker)
setStart(((Blocker)target).gap);
else
Gdx.app.logError("Target is not a blocker: " + target.toString());
super.begin();
}
protected void update (float percent) {
super.update(percent);
if (target instanceof Blocker)
((Blocker)target).gap = getValue();
}
}
Fade In Action for example :
actor.AddAction(Actions.fadeIn(2.0f));

How to access Physics World in Layer

I need to create joint between two bodies in layer. Joints are to be added in physics world. How can i access physics world in layer?
My JavaScript implementation. Hope it will help.
var space;
function initPhysics() {
space = new cp.Space();
space.gravity = cp.v(0, -800);
space.iterations = 30;
space.sleepTimeThreshold = Infinity;
space.collisionSlop = Infinity;
}
function addJoints() {
chainTableJoint1 = new cp.PivotJoint(chainEnd1, tableBackBody, cp.v.add(cp.v(chainEnd1.getPos().x, tableBackNode.getPosition().y + (tableBackNode.getContentSize().height * 0.5)), boxOffset));
chainTableJoint2 = new cp.PivotJoint(chainEnd2, tableBackBody, cp.v.add(cp.v(chainEnd2.getPos().x, tableBackNode.getPosition().y + (tableBackNode.getContentSize().height * 0.5)), boxOffset));
space.addConstraint(chainTableJoint1);
space.addConstraint(chainTableJoint2);
}
you have four options:
1)- override Layer::onEnter() or onEnterTransitionDidFinish ()
methods then access from theme like this:
Layer::onEnter(){
Layer::onEnter();
auto world = _director->getRunningScene()->getPhysicsWorld();
}
2)- create a custom Layer::createScene() method then access from Layer::init() like this:
Scene* GameScene::createScene()
{
auto layer = new (std::nothrow) GameScene;
if (layer)
{
auto scene = Scene::createWithPhysics();
layer->autorelease();
scene->addChild(layer);
if (layer->init()) return scene;
}
CC_SAFE_DELETE(layer);
return nullptr;
}
// then in Layer::init() you do this:
Layer::init(){
auto world = _director->getRunningScene()->getPhysicsWorld();
}
3)- add a PhysicsWorld getter method to the director (involves some library code customization's):
first go to CCDirector.h and then add a forward declaration of the scene class under NS_CC_BEGIN like this:
NS_CC_BEGIN
class cocos2d::Scene;
then go to the private section of the Director class and add these two lines like this:
private:
cocos2d::PhysicsWorld* _myPhysicsWorld;
friend class Scene;
then go to the public section of the Director class and add this getter method like this:
public:
cocos2d::PhysicsWorld* getWorld() const{
return _myPhysicsWorld;
};
this is an overview of the changes made in CCDirector.h file:
// CCDirector.h
NS_CC_BEGIN
// 1
class cocos2d::Scene;
class Director : public Ref{
public:
//2
cocos2d::PhysicsWorld* getWorld() const{
return _myPhysicsWorld;
};
private:
// 3
cocos2d::PhysicsWorld* _myPhysicsWorld;
friend class cocos2d::Scene;
};
NS_CC_END
so after that we go to CCScene.cpp into a method with this signature (bool Scene::initWithPhysics()) in it you will find a call to PhysicsWorld::construct(this) add just right after that method call this line:
_director->_myPhysicsWorld = _physicsWorld;
and this should be the overview of what we did in CCScene.cpp:
// CCScene.cpp
class Scene : public Node{
bool Scene::initWithPhysics(){
_physicsWorld = PhysicsWorld::construct(this);
// 4 since Director is a singleton class, we can access its instance from anywhere
_director->_myPhysicsWorld = _physicsWorld;
}
};
now as soon as Scene::createWithPhysics() gets called anywhere the director will get a copy of the PhysicsWorld pointer which can be accessed using our director getWorld() method anywhere anytime!! (because the director is a singleton as you know) and thats all without exposing _myPhysicsWorld to the user meaning he can only read _myPhysicsWorld from the outside!!
4)- make your own Custom PhysicsWorld class and since PhysicsWorld::construct() is protected which means it can be easily inherited.
// PhysicsManager.h
class PhysicsManager : public cocos2d::PhysicsWorld
{
public:
static PhysicsManager* createWorld(cocos2d::Scene* scene) {
_myPhysicsWorld = PhysicsWorld::construct(scene);
}
PhysicsWorld* getWorld() const { return _myPhysicsWorld; }
private:
static cocos2d::PhysicsWorld* _myPhysicsWorld;
};
//PhysicsManager.cpp
PhysicsManager::PhysicsWorld* _myPhysicsWorld;
now you can use it like this:
Layer::init(){
auto physicsManager = PhysicsManager::createWorld(this->getScene());
auto world = physicsManager->getWorld();
}
remember that you can even make it a singleton class if you want to!
Edit:
I forgot to mention that there is another good solution in here:
http://discuss.cocos2d-x.org/t/physics-joint-distance-problem/17926/2

After adding a TableRowSorter adding values to model cause java.lang.IndexOutOfBoundsException: Invalid range

After adding a TableRowSorter to a table and its corresponding model any corresponding adds specifically at firetabletablerowsinserted cause exceptions. It is clear from testing that the GetRowCount() is returning a value past the models range. However it does not make sense to me how to continue to add values to the table after a sorter or filter has been added?
As an example, I set the row filter before adding anything to the table then add a value to the table with the following calls in my model:
this.addRow(row, createRow(trans,row));
this.fireTableRowsInserted(this.getRowCount(), this.getRowCount());
The rowcount is of size 1 and the exception is thrown:
java.lang.IndexOutOfBoundsException: Invalid range
at javax.swing.DefaultRowSorter.checkAgainstModel(Unknown Source)
at javax.swing.DefaultRowSorter.rowsInserted(Unknown Source)
at com.gui.model
If I do the same steps without first adding the sorter everything is fine. I assumed that possibly I needed to notify the model that the sorter may have made changes and tried the following but still returns an exception:
this.addRow(row, createRow(trans,row));
this.fireTableStructureChanged()
this.fireTableRowsInserted(this.getRowCount(), this.getRowCount());
I even tried to notify the sorter inside the model that a value has been added to the model before calling fire like below but it fails as well:
this.addRow(row, createRow(trans,row));
if(sorter.getRowFilter() != null){
//if a sorter exists we are in add notify sorter
sorter.rowsInserted(getRowCount(), getRowCount());
}
this.fireTableRowsInserted(this.getRowCount(), this.getRowCount());
Lastly, I hard coded the FireTableRowsInsterted(0,0) and it does not throw any exception. But nothing gets added to table? So, I know it is definitely some type of OutOfBounds issue.
I have looked all over and cannot seem to find the answer. If anyone has any idea how this is suppose to work it be very helpful.
Here is code that sets the sorter inside jpanel:
messageTable.setRowSorter(null);
HttpTransactionTableModel m = getTransactionTableModel();
final int statusIndex = m.getColIndex("status");
RowFilter<Object,Object> startsWithAFilter = new RowFilter<Object,Object>() {
public boolean include(Entry<? extends Object, ? extends Object> entry) {
for(char responseCode:responseCodes)
{
if (entry.getStringValue(statusIndex).startsWith(Character.toString(responseCode))) {
return true;
}
}
// None of the columns start with "a"; return false so that this
// entry is not shown
return false;
}
};
m.sorter.setRowFilter(startsWithAFilter);
messageTable.setRowSorter(m.sorter);
Here is code inside my model that adds value to model:
public void update(Observable o, Object evt) {
if (evt instanceof ObservableEvent<?>) {
ObservableEvent<?> event = (ObservableEvent<?>) evt;
if (event.getElement() instanceof HttpTransaction) {
HttpTransaction trans = (HttpTransaction) event.getElement();
// handle adding of an element
if (event.getAction() == PUT) {
if (includeTransaction(trans)) {
// handle request elements
if (trans.getRequest() != null && idMap.get(trans.getID()) == null) {
idMap.put(trans.getID(), count++);
// transactionManager.save(trans);
int row = idMap.get(trans.getID());
this.addRow(row, createRow(trans,row));
if(sorter.getRowFilter() != null){
sorter.rowsInserted(getRowCount(), getRowCount());
}
this.fireTableRowsInserted(this.getRowCount(), this.getRowCount());
}
You have an out by 1 error. The correct code for firing the event is:
this.fireTableRowsInserted(this.getRowCount()-1, this.getRowCount()-1);
I went back and had a better look at this after seeing kleopatra's comment. I was changing my TableModel after creating a RowSorter, but before attaching the RowSorter to the JTable. Here's an example that shows the problem I was having.
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableRowSorter;
import java.util.ArrayList;
import java.util.List;
public class TestTableMain {
public static void main(String[] args) {
new TestTableMain();
}
public TestTableMain() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
buildAndShowMainFrame();
}
});
}
private void buildAndShowMainFrame() {
JFrame frame = new JFrame();
JScrollPane scrollPane = new JScrollPane();
TestTableModel model = new TestTableModel();
JTable table = new JTable(model);
TableRowSorter<TestTableModel> rowSorter = new TableRowSorter<>(model);
rowSorter.setRowFilter(null);
model.add("First added item.");
/* The RowSorter doesn't observe the TableModel directly. Instead,
* the JTable observes the TableModel and notifies the RowSorter
* about changes. At this point, the RowSorter(s) internal variable
* modelRowCount is incorrect. There are two easy ways to fix this:
*
* 1. Don't add data to the model until the RowSorter has been
* attached to the JTable.
*
* 2. Notify the RowSorter about model changes just prior to
* attaching it to the JTable.
*/
// Uncomment the next line to notify rowSorter that you've changed
// the model it's using prior to attaching it to the table.
//rowSorter.modelStructureChanged();
table.setRowSorter(rowSorter);
scrollPane.setViewportView(table);
frame.setContentPane(scrollPane);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
model.add("Second added item.");
}
private class TestTableModel extends AbstractTableModel {
private List<String> items = new ArrayList<>();
public TestTableModel() {
for(int i=0;i<5;i++) {
add("Item " + i);
}
}
#Override
public int getRowCount() {
return items.size();
}
#Override
public int getColumnCount() {
return 1;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return items.get(rowIndex);
}
public void add(String item) {
items.add(item);
fireTableRowsInserted(items.size() - 1, items.size() - 1);
}
}
}
So, for now it looks like if you check in your model if your currently in sorting mode and if that is case only call update on sorting model. Otherwise call normal model fire updates everything seems to work so far. I'm still open for better ways to handle this though:
if(sorter.getRowFilter() != null){
sorter.modelStructureChanged();
}
else
this.fireTableRowsInserted(this.getRowCount(), this.getRowCount());