patternModerate
Game with tile map - Sprite-Kit
Viewed 0 times
mapspritewithkitgametile
Problem
I'm a novice programmer learning Objective-C in my spare time. I would greatly appreciate any help or advice with my code. I want to follow best practices whenever possible. I know that I am missing some foundational stuff with my code, so please point that out where you see it. Things like when to make variables instance variables versus properties, when to define things like (strong) for properties, when and where to instantiate variables, etc.
I'm building a simple game to practice and to learn Sprite-Kit. I've been working on it for a few days, and it does function mostly as I want it to. The game model is pure objective-c and generates a map of tiles as well as handles inserting tiles into the map. This is done with an NSDictionary with the keys being the coordinates of the tiles. That code is not included below, but I can post it if need be. My SKScene renders those tiles based on their type, and tells the model to insert new tiles where the screen is tapped. It also manages the touch controls.
The main problems are that the panning around the world and the pinching to zoom move much faster than I would like. I can't figure out how to slow them down, and I'm wondering if I am doing something wrong.
Please let me know if you need to see more code to review it. And please don't hesitate to point out any flaws that you see, both in style and in substance.
Here is the header:
And now the implementation:
```
enter code here
// TPGameSceneSO.m
#import "TPGameSceneSO.h"
#define TILE_SIZE CGSizeMake(128,128)
#define TILE_DI
I'm building a simple game to practice and to learn Sprite-Kit. I've been working on it for a few days, and it does function mostly as I want it to. The game model is pure objective-c and generates a map of tiles as well as handles inserting tiles into the map. This is done with an NSDictionary with the keys being the coordinates of the tiles. That code is not included below, but I can post it if need be. My SKScene renders those tiles based on their type, and tells the model to insert new tiles where the screen is tapped. It also manages the touch controls.
The main problems are that the panning around the world and the pinching to zoom move much faster than I would like. I can't figure out how to slow them down, and I'm wondering if I am doing something wrong.
Please let me know if you need to see more code to review it. And please don't hesitate to point out any flaws that you see, both in style and in substance.
Here is the header:
// TPGameSceneSO.h
#import
#import "TPGame.h"
//set up for 60 frames per second
#define kMinTimeInterval (1.0f / 60.0f)
//seems to run better with the delegate enabled
@interface TPGameSceneSO : SKScene
@property TPGame *theGame;
@property SKSpriteNode *tileMapNode;
@property SKSpriteNode *movableSprites;
@property UIPinchGestureRecognizer *pinchRecognizer;
@property UIPanGestureRecognizer *panRecognizer;
@endAnd now the implementation:
```
enter code here
// TPGameSceneSO.m
#import "TPGameSceneSO.h"
#define TILE_SIZE CGSizeMake(128,128)
#define TILE_DI
Solution
Instance Variables and Properties
Understanding exactly what a
An instance variable is just that. An instance variable. It's pretty straight forward. It's just a variable in that can be accessed by all the methods in your class. And if it's a public variable, it can be accessed outside the class as well.
A
Consider
What have we actually done? As it turns out, this is the equivalent of doing this:
So by default, a
But consider this case:
By declaring
So, the other thing left is that a
Now then, when should you use an
Well, it really doesn't matter too terribly much. If you need a variable to be visible outside the class, you can still use an instance variable and still give it a getter and setter. The only difference between writing a getter, setter, creating an instance variable and just using a
And the cool thing is, you don't have to limit yourself to the traditional idea of a setter, getter, and instance variable. You can create dot-syntax methods any time you need a method that takes no arguments and returns a value.
Please let me know if you would like some more information about properties/instance variables.
Simon's answer does make a good recommendation about condensing your
BUT... if you're doing this, let's use an
So now our switch can look like this:
Of course, the names should be chosen for something that's appropriately descriptive in your case. The point here is we've made our code more self-documenting.
It's important for our code to be easy to read. Code is written for humans and no one likes writing comments, so let's make our code more readable by using good variable names as well as using enums.
Understanding exactly what a
@property is is absolutely crucial to being a good Objective-C programmer. Here's my crash course.An instance variable is just that. An instance variable. It's pretty straight forward. It's just a variable in that can be accessed by all the methods in your class. And if it's a public variable, it can be accessed outside the class as well.
A
@property, however, is different. A @property doesn't even necessarily have an instance variable behind it. It does by default, but a @property is much more than just an instance variable. Moreover, you can have public AND private @property variables. Simon's comments on properties versus variables are inaccurate.Consider
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@endWhat have we actually done? As it turns out, this is the equivalent of doing this:
@interface Person : NSObject {
@private
NSString *name;
}
- (void)setName:(NSString*)aName;
- (NSString*)name;
@end
@implementation Person
- (void)setName:(NSString*)aName {
name = aName;
}
- (NSString*)name {
return name;
}So by default, a
@property creates three things: an instance variable, a setter, and a getter.But consider this case:
@interface Person : NSObject
@property NSString *firstName;
@property NSString *lastName;
@property (readonly) NSString *fullName;
@end
@implementation Person
- (NSString*)fullName {
return [NSString stringWithFormat:"%@ %@", self.firstName, self.lastName];
}
@endBy declaring
fullName as a readonly property, we've prevented the creation of a setter method. But in the @implementation, what we've also done is overridden the getter method. But something very important happened in this method. We made no reference to _fullName, which would be the instance variable that a @property called fullName would create. As such, we've also prevented the creation of an instance variable.So, the other thing left is that a
@property allows you to use the dot-syntax to access the setters and getters (though you don't have to use it).Now then, when should you use an
@property and when should you use an instance variable?Well, it really doesn't matter too terribly much. If you need a variable to be visible outside the class, you can still use an instance variable and still give it a getter and setter. The only difference between writing a getter, setter, creating an instance variable and just using a
@property? Dot-syntax, that's it.And the cool thing is, you don't have to limit yourself to the traditional idea of a setter, getter, and instance variable. You can create dot-syntax methods any time you need a method that takes no arguments and returns a value.
Please let me know if you would like some more information about properties/instance variables.
Simon's answer does make a good recommendation about condensing your
renderTile: method. Although, I'd do it in a different way. Personally, I like switch statements. You can keep the switch and still condense the code:-(SKSpriteNode *)renderTile: (int)tileType {
switch(tileType) {
case 1:
// do stuff
break;
case 2:
case 3:
case 4:
case 5:
case 6:
// do stuff
break;
default:
// do stuff
break;
}
}BUT... if you're doing this, let's use an
enum, shall we? typedef NS_ENUM(unsigned short, MyTileTypeEnum) {
BlackTile = 1,
TileTextureA = 2,
TileTextureB = 3,
TileTextureC = 4,
TileTextureD = 5,
TileTextureE = 6
};So now our switch can look like this:
switch(tileType) {
case BlackTile:
// do stuff
break;
// ... etcOf course, the names should be chosen for something that's appropriately descriptive in your case. The point here is we've made our code more self-documenting.
It's important for our code to be easy to read. Code is written for humans and no one likes writing comments, so let's make our code more readable by using good variable names as well as using enums.
Code Snippets
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@end@interface Person : NSObject {
@private
NSString *name;
}
- (void)setName:(NSString*)aName;
- (NSString*)name;
@end
@implementation Person
- (void)setName:(NSString*)aName {
name = aName;
}
- (NSString*)name {
return name;
}@interface Person : NSObject
@property NSString *firstName;
@property NSString *lastName;
@property (readonly) NSString *fullName;
@end
@implementation Person
- (NSString*)fullName {
return [NSString stringWithFormat:"%@ %@", self.firstName, self.lastName];
}
@end-(SKSpriteNode *)renderTile: (int)tileType {
switch(tileType) {
case 1:
// do stuff
break;
case 2:
case 3:
case 4:
case 5:
case 6:
// do stuff
break;
default:
// do stuff
break;
}
}typedef NS_ENUM(unsigned short, MyTileTypeEnum) {
BlackTile = 1,
TileTextureA = 2,
TileTextureB = 3,
TileTextureC = 4,
TileTextureD = 5,
TileTextureE = 6
};Context
StackExchange Code Review Q#40471, answer score: 10
Revisions (0)
No revisions yet.