Let me see if I can articulate what I'm trying to do... I'll distill it to the core issue.
I have an objective-c program and a c callback function. The context is I am using cocos2d and chipmunk physics with the iphone sdk. What I am trying to do is update "score" upon a collision between a bullet and a monster. Everything works fine except for updating the score.
the game logic is in obj-c but the actual collision logic is done in a c function that gets called when things collide. For example, it is there that I render the flames/explosion of the collision. It is also there that I want to update the score.
Here's the problem:
But score is an instance variable of the "GAME" object and I do not have visibility into that instance variable. I suppose I can pass into the c function another parameter by reference called &addscore or something, but was wondering if there is a more obvious way to do it since there might be a bunch of other variables beyond 'score' that must be updated upon the collission.
the net is I need variables in the object to be seen by the c function, and vice versa: those variables set in the function to be seen in the object.
thanks in advance.
Your knowledge and thoughts about gaining access to Obj-C instance variables within C code by passing them by reference seems correct.
If you need to pass a number of variables I assume they collectively make up some kind of "game state" description. Perhaps these could be grouped into a seperate object or structure and passed into the C function via a single parameter?
As an example, the following class:
typedef struct GameState {
int score;
int numberOfBulletsLeft;
} GameState;
#interface GAME : NSObject {
GameState state;
}
...
#end
Would work well with a C function such as the following
void myCFunctionThatDoesCollisiondetectionEtc(GameState * state) {
NSLog(#"You have %d bullets left", state->numberOfBulletsLeft);
}
If your existing GAME object has suitable properties or messages, you may even be able to do something like the following, where you simply pass your entire Objective-C object:
void myCFunctionThatDoesCollisionDetectionEtc(GAME * myGame) {
if (...)
[myGame increaseScore:50];
else
[myGame decreaseScore:50];
}
A third alternative would be to change the return value of your C function to indicate if a collision has been detected and then leave it up to the Objective-C code within the GAME class to update the score and any other actions which may need to occur.
To improve on that last answer a bit more, you can do the following:
cpSpaceAddCollisionPairFunc( space, 1, 2, (cpCollFunc)functionName, game);
void functionName( cpShape *a, cpShape *b, cpContact *contacts, int numContacts, cpFloat normal_coef, GameClass *game) {
[game doSomethingToScoreSomething];
}
No need to cast the pointer inside of the function, you can cast the function pointer instead. That's what I've done internally with the Chipmunk source and it's a lot cleaner.
No, you do not need variables in your object to be visible by the function. That breaks encapsulation, and it's a bad idea. When you want an object to do something (like changing some internal value such as the score) you should provide a method to accomplish that effect.
If you allow code outside your class to alter your instance variables, then you're throwing away a key advantage of object-oriented programming.
If the game object is a singleton you can access it from any scope (which includes your C callback). You would make a singleton if you only ever want one instance of some object to exist. A singleton can always be reached from anywhere by sending a message to the class to retrieve the singleton instance:
[Game sharedGameInstance];
Alternatively, chipmunk allows for you to pass a void * data to the callback. This is to accommodate the programmer to send information he needs to the callback.
You can send a pointer to your game object instance in that void * to the callback, like so:
cpSpaceAddCollisionPairFunc( space, 1, 2, &functionName, (void *)game );
void functionName( cpShape *a, cpShape *b, cpContact *contacts, int numContacts, cpFloat normal_coef, void *data ) {
GameClass * game = (GameClass *)data;
// do whatever you need here. You can call messages on game as per usual.
}
Related
Instead of writing a code like
FindObjectOfType<GameManager>().gameOver()
I would like to type just
gm.gameOver()
Is there a way to do that in Unity?
Maybe using some kind of alias, or some kind of namespace or something else. I am after making my code clean, so using GameManger gm = FindObjectOfType() in every file that uses a the GameManager is not what I am looking for.
In general I have to discourage this question. This is very questionable and I would actually not recommend this kind of shortening aliases for types and especially not for a complete method call ... bad enough when it is done with variables and fields by a lot of people.
Always use proper variable and field names thus that by reading the code you already know what you are dealing with!
how about storing it in a variable (or class field) at the beginning or whenever needed (but as early as possible)
// You could also reference it already in the Inspector
// and skip the FindObjectOfType call entirely
[SerializeField] private _GameManager gm;
private void Awake()
{
if(!gm) gm = FindObjectOfType<_GameManager>();
}
and then later use
gm.gameOver();
where needed.
In general you should do this only once because FindObjectOfType is a very performance intense call.
This has to be done of course for each class wanting to use the _GameManager instance ...
However this would mostly be the preferred way to go.
Alternatively you could also (ab)use a Singleton pattern ... it is controversial and a lot of people hate it kind of ... but actually in the end FindObjectOfType on the design side does kind of the same thing and is even worse in performance ...
public class _GameManager : MonoBehaviour
{
// Backing field where the instance reference will actually be stored
private static _GameManager instance;
// A public read-only property for either returning the existing reference
// finding it in the scene
// or creating one if not existing at all
public static _GameManager Instance
{
get
{
// if the reference exists already simply return it
if(instance) return instance;
// otherwise find it in the scene
instance = FindObjectOfType<_GameManager>();
// if found return it now
if(instance) return instance;
// otherwise a lazy creation of the object if not existing in scene
instance = new GameObject("_GameManager").AddComponent<_GameManager>();
return instance;
}
}
private void Awake()
{
instance = this;
}
}
so you can at least reduce it to
_GameManager.Instance.gameOver();
the only alias you can create now would be using a using statement at the top of the file like e.g.
using gm = _GameManager;
then you can use
gm.Instance.gameOver();
it probably won't get much shorter then this.
But as said this is very questionable and doesn't bring any real benefit, it only makes your code worse to read/maintain! What if later in time you also have a GridManager and a GroupMaster? Then calling something gm is only confusing ;)
Btw you shouldn't start types with a _ .. rather call it e.g. MyGameManager or use a different namespace if you wanted to avoid name conflicts with an existing type
So I create my class Cars. Then I make a variable(audi) for an object from my class cars. Everything is fine and dandy but I noticed that I can create an object(with an engine value of 50) without specifying a variable for it to be held in. So now how can I access that object?
#include <iostream>
using namespace std;
class Cars
{
public:
int getStatus();
Cars(int engine=5);
private:
int m_engine;
};
Cars::Cars(int engine)
{
m_engine=engine;
cout<<"A new car is made."<<endl;
}
Cars::getStatus()
{
cout<<m_engine<<endl;
}
int main()
{
Cars audi(10);
audi.getStatus();
Cars(50);
}
It depends on when you want to access the object.
Cars(50);
With this piece of code, you create a temporary object that lives only during execution of the current statement (i. e. until execution of your code passes the semicolon).
Cars(50);
// I want to access the object here
In this case: Too late. The temporary has already been destroyed and doesn't exist any more. No chance to get back to it. You can, however, use the object as long as it lives, e. g. call a member function on it or pass it to another function:
Cars(10).doSomething();
// but right now (after the semicolon), the car doesn't exist any more
doSomethingElse(Cars(12));
// again, the object got destroyed
Be aware that in above example, you created two distinct instances, each ceasing to exist when reaching the semicolon. Be aware, too, that the objects' destructors get called at this point of time.
You need to do it all together, like this:
Cars(50).getStatus();
Otherwise you won't have a way to refer to your car with 50 m_engine.
This temporary should be used with fidelity. Read more in What is an Anonymous Object?
You can't! It's already dead by the time you try. Cars(50) is a temporary, and its lifetime ends at the end of its full-expression -- that is, at the ;.
I am trying to instantiate a GameObject and keep a reference to it but for some reason the above error appears every time it is instantiated even though the instantiation still goes through. The line of code it points me to is this: GameObject next = Instantiate(prefab); Like I said, the instantiation still works correctly, but in the interest of stability, I would like to get rid of this error. What does Unity want from me?
You're all wrong. Roughly speaking, Instantiate returns
WHAT YOU PASS IN.
if you have this ...
public GameObject modelDinosaur;
you can indeed have this
GameObject nu = Instantiate(modelDinosaur);
No need to cast. (It's totally OK to cast if you want to.)
Yes, for a prefab, do exactly what everyone tells you above
GameObject nu = (GameObject)Instantiate(yourPrefab);
BTW it is idiomatic to use "nu" (like "new") as the temporary variable. ("new" is a keyword of course, you can't use that.)
Most commonly you then do these things ..
GameObject nu = Instantiate(modelDinosaur);
YourDinoScript nuD = nu.GetComponent<YourDinoScript>();
yourDinoList.Add(nuD);
nu.name = "dynamic " + counter;
nuT = nu.transform;
nuT = blah blah
nuT = your holder
nuT = logic position
etc etc
PS: regarding Unity's doco, you might as well read the ravings of a drunk chatbot. Forget it.
The Unity Instantiate method has a return type of Object. You need to instantiate your prefab as a GameObject if you want to store it in a GameObject variable.
Assuming you are using C#, you can instantiate a GameObject and store it in a variable like so:
GameObject myGameObject = Instantiate(prefab) as GameObject;
Instantiate() return an Object, You need to cast it to GameObject Explicitly.
Try this:
GameObject next = (GameObject)Instantiate(prefab);
More information:
Instantiate() signature: public static Object Instantiate(Object original)
This clearly shows that the return type is Object and not Gameobject
Reference
Please refer to this for more details
Alright so I've been continuing to learn about classes and oop languages. And am a bit confused.
If I was to have a separate class for player stats. And in that class I have some private ints and then some functions to change them publicly.
Say I want to change and get those ints From my main class. I make an object and assign them to local variables then I can call the local variables in my main script. Then update the variable in the stat class.
It seems a little silly that I have to make a local variable as well as a separate variable in a different class.
To me it would make sense to just be able to call the separate class in a new object whenever I wanted to access the variables in the stat class but I can't...
Let me know if this isn't clear as I can try to expand more.
Thanks
Ben
You do not have to make new variables in the "main" class ....
you can just use the getters and setters through the object that you created.
Also copying variables from player stats to main class is not a good idea because now you have to maintain two copies of same data, at least until you are in scope of main class. If not handled correctly it can also cause data inconsistencies.
Assuming you are using Java, you can do this.
public class PlayerStats{
private int var1=20;
public void setVar1(int var1){
this.var1=var1
}
public int getVar1(){
return var1
}
}
public class mainClass{
PlayerStats pStats = new PlayerStats();
pStats.getVar1();
pStats.setVar1(14);
System.out.println(pStats.getVar1());
}
Thanks for that answer definately cleared things up however, in the object created in mainClass if I create the object in one function how do I use it in another function in the same class?
Depends on how and if the two functions are connected and how central that object is to your class.
If the object is very central to class :
That is, you are using it almost in all the function, your class revolves around playing with that object, then you can create it at class level something along these lines
public class mainClass{
PlayerStats pStats = new PlayerStats();
public void function1() {
pStats.setVar1(14);
System.out.println(pStats.getVar1());
}
public void function2(int x) {
pStats.setVar1(x);
System.out.println(pStats.getVar1());
}
}
If two functions are not connected :
Just make a new object inside the function scope, if possible.
This is better than creating an object at class level, because the object becomes eligible for garbage collection after the function is finished executing. Whereas, the object created at class level stays in the memory as long as the object (instance of main class) is in the memory.
If two functions are connected, i.e you are calling one function from inside the second function :
you can just pass the object as an argument, something along these lines
public class mainClass{
public void function1() {
PlayerStats pStats = new PlayerStats();
pStats.setVar1(14);
function2(pStats)
}
public void function2(PlayerStats x) {
System.out.println(pStats.getVar1());
}
}
Also google dependency injection, it is an important concept, try to use it as often as possible. It produces good decoupled and testable design
There is so much more to say, people have written books on this topic, OO Design is an art in itself.
So I want to add achievements to my game.
Basically there are around 40 achievements that can be awarded while using the app. (if while playing a game, and even while pressing some menu buttons).
I'm not sure how should I implement it, so I'll let you know what are the options I thought of so far :
Writing an AM (Achievements Manager) class which will have a addAchievment() function.
Inside every function in my app that can grant achievement I can allocate an Achievemnt object and call addAchievment() with that object.
What I don't like about this approach is first, you have do add lot's of achievments code to many many parts of the app. (and also checking not add the same achievement more than once).
One way to improve it would be maybe to call addAchievment() with a certain enum, and then inside addAchievment() implementation to check each enum and allocate the appropriate achievment object - however, a function with a switch of 40 cases doesn't sound good either.
2.
For every class that can report achievements I can write a function per achievement which return if that achievement should be granted.
for example is class A can report 2 achivments I can write 2 functions :
-(BOOL) shouldGrantA1
-(BOOL) shouldGrantA2
When I init class A, I call the achievements manger and add those 2 function to an array of function the AM will hold.
Every time I want to check if I should grant achievments I just call the AM CheckAchievements() and what it will do is run through all the function and add achievements
where the function return TRUE.
Problem with this approach - Let's say in class A I reach a place where I change a value that I know can grant achievemetn. I can call AM's CheckAchievements() but that will go through all the achivements functions, even though probably currently only class A's achivement would be granted. seems like a bit overhead.
Any way to solve that ?
I would love to here other suggestion as well.
Thanks!!
I would not add any achievement like code to your existing game classes. No booleans or whatsoever because this creates too tight a coupling between your game classes and your achievement system. Better to create a separate "AchievementManager" that manages several AchievementListeners, these listen to the state of objects and when a relevant state changes the unlock condition is checked. I think this idea is best illustrated in code.
For example if you have the achievement "Player walks 100 kilometers". the PlayerWalksAchievementListener would look like this.
private AchievementManager manager;
private Player player.
private Vector2 previousPlayerPosition;
private float distanceWalked;
Update()
{
float dist = Vector2.Distance(player.Position, previousPlayerPosition);
if(dist > 0)
{
distanceWalked += dist;
CheckUnlockCondition();
}
}
CheckUnlockCondition()
{
if(distanceWalked * conversionFactor > 100) { manager.UnlockAchivement(achievementID); }
}