
Game Scene 1: 3D Room with Isgl3D
more planes
So it's time to take the Away3D version of my first Game Scene example and bring it to the Iphone. For this, I'll use a framework called Isgl3D which I think is the most similar one to Away3D in the way it accomplishes things. And I find it far less confusing than Cocos3D. Plus it offers the ability to create primitives, which is something I like in Away3D, not being much of a 3D modeler myself.
There is quite a lot to cover with Isgl3D, and I'll post a series of tutorials tackling the many different topics individually. But for now I'll post here the complete code and source files for the first example.
If you saw the Away3D version you know I used Box2D for collision. I kept Box2D with Isgl3D because its built in Bullet Physics engine is too erratic.
Unfortunately there is no built in support for Box2D in Isgl3D (and when I say support I mean the possibility to draw the debug data created by Box2D.)
But aside from that, I must say I like Isgl3D quite a lot and I can see it as an extremely helpful tool in the creation of some interesting games. The one bad thing I find is that it does not support texture atlases for the textures. But I'm sure this will change, or if not, I will try to add the support for it.
So I'll continue posting some more Game Scene examples and using Isgl3D to bring it to the Iphone. Later I may do the same but with Unity3D.
But for now, you can download ISGL3D from here.
The Interface
#import "isgl3d.h"
#import "Box2D.h"
enum {
MOVE_LEFT,
MOVE_RIGHT,
MOVE_UP,
MOVE_DOWN
};
@interface HelloWorldView : Isgl3dBasic3DView {
Isgl3dNode * _container;
Isgl3dMeshNode * _player;
NSMutableArray * _crates;
NSArray * _frames_back;
NSArray * _frames_side;
NSArray * _frames_front;
b2World* _world;
b2Body * _b2Player;
b2Body *_boxes2[6];
float _speed;
float _scale;
float _wallHeight;
float _roomSide;
float _boxSide;
float _playerWidth;
float _playerHeight;
int _direction;
int _animationCnt;
int _frameIndex;
BOOL _animate;
CGPoint _touchLocation;
CGPoint _center;
CGSize _screenSize;
}
-(b2Body *) createBodyAt:(CGPoint) pos withSize:(CGSize) size ofType:(b2BodyType) type;
-(void) makeBoxAt:(CGPoint) pos withIndex:(int)index;
-(void) updatePlayer;
-(void) transFormObject:(b2Body *) body1 threeD:(Isgl3dMeshNode *) body2 andRotate:(BOOL) rotate;
@end
The Implementation Class
#import "HelloWorldView.h" #import#import #define PTM_RATIO 32 @implementation HelloWorldView - (id) init { if ((self = [super init])) { //room dimensions and element positions _wallHeight = 4; _roomSide = 12; _boxSide = 1.4; _playerWidth = 1.5; _playerHeight = 3; _animationCnt = 0; _frameIndex = 0; NSArray *cratePosition = [NSArray arrayWithObjects: [NSValue valueWithCGPoint:CGPointMake(6,6)], [NSValue valueWithCGPoint:CGPointMake(2,6)], [NSValue valueWithCGPoint:CGPointMake(4,10)], [NSValue valueWithCGPoint:CGPointMake(8,5)], [NSValue valueWithCGPoint:CGPointMake(6,4)], [NSValue valueWithCGPoint:CGPointMake(7,9.5f)], nil]; //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ISGL3D &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& [self.camera setPosition:iv3(0, 1, 7)]; [self.camera lookAt:0 y:0 z:0]; _container = [[self.scene createNode] retain]; //MATERIALS Isgl3dTextureMaterial * wallMaterial = [Isgl3dTextureMaterial materialWithTextureFile:@"wall.png" shininess:0 precision:Isgl3dTexturePrecisionMedium repeatX:NO repeatY:NO]; Isgl3dTextureMaterial * groundMaterial = [Isgl3dTextureMaterial materialWithTextureFile:@"ground.png" shininess:0 precision:Isgl3dTexturePrecisionMedium repeatX:YES repeatY:YES]; Isgl3dTextureMaterial * playerMaterial_front0 = [Isgl3dTextureMaterial materialWithTextureFile:@"player_front_0.png" shininess:0 precision:Isgl3dTexturePrecisionMedium repeatX:NO repeatY:NO]; Isgl3dTextureMaterial * playerMaterial_front1 = [Isgl3dTextureMaterial materialWithTextureFile:@"player_front_1.png" shininess:0 precision:Isgl3dTexturePrecisionMedium repeatX:NO repeatY:NO]; Isgl3dTextureMaterial * playerMaterial_front2 = [Isgl3dTextureMaterial materialWithTextureFile:@"player_front_2.png" shininess:0 precision:Isgl3dTexturePrecisionMedium repeatX:NO repeatY:NO]; Isgl3dTextureMaterial * playerMaterial_front3 = [Isgl3dTextureMaterial materialWithTextureFile:@"player_front_3.png" shininess:0 precision:Isgl3dTexturePrecisionMedium repeatX:NO repeatY:NO]; _frames_front = [[NSArray arrayWithObjects:playerMaterial_front0, playerMaterial_front1, playerMaterial_front2, playerMaterial_front3, nil] retain]; Isgl3dTextureMaterial * playerMaterial_back0 = [Isgl3dTextureMaterial materialWithTextureFile:@"player_back_0.png" shininess:0 precision:Isgl3dTexturePrecisionMedium repeatX:NO repeatY:NO]; Isgl3dTextureMaterial * playerMaterial_back1 = [Isgl3dTextureMaterial materialWithTextureFile:@"player_back_1.png" shininess:0 precision:Isgl3dTexturePrecisionMedium repeatX:NO repeatY:NO]; Isgl3dTextureMaterial * playerMaterial_back2 = [Isgl3dTextureMaterial materialWithTextureFile:@"player_back_2.png" shininess:0 precision:Isgl3dTexturePrecisionMedium repeatX:NO repeatY:NO]; Isgl3dTextureMaterial * playerMaterial_back3 = [Isgl3dTextureMaterial materialWithTextureFile:@"player_back_3.png" shininess:0 precision:Isgl3dTexturePrecisionMedium repeatX:NO repeatY:NO]; _frames_back = [[NSArray arrayWithObjects:playerMaterial_back0, playerMaterial_back1, playerMaterial_back2, playerMaterial_back3, nil] retain]; Isgl3dTextureMaterial * playerMaterial_side0 = [Isgl3dTextureMaterial materialWithTextureFile:@"player_side_0.png" shininess:0 precision:Isgl3dTexturePrecisionMedium repeatX:NO repeatY:NO]; Isgl3dTextureMaterial * playerMaterial_side1 = [Isgl3dTextureMaterial materialWithTextureFile:@"player_side_1.png" shininess:0 precision:Isgl3dTexturePrecisionMedium repeatX:NO repeatY:NO]; Isgl3dTextureMaterial * playerMaterial_side2 = [Isgl3dTextureMaterial materialWithTextureFile:@"player_side_2.png" shininess:0 precision:Isgl3dTexturePrecisionMedium repeatX:NO repeatY:NO]; Isgl3dTextureMaterial * playerMaterial_side3 = [Isgl3dTextureMaterial materialWithTextureFile:@"player_side_3.png" shininess:0 precision:Isgl3dTexturePrecisionMedium repeatX:NO repeatY:NO]; _frames_side = [[NSArray arrayWithObjects:playerMaterial_side0, playerMaterial_side1 , playerMaterial_side2 , playerMaterial_side3, nil] retain]; Isgl3dTextureMaterial * crateMaterial = [Isgl3dTextureMaterial materialWithTextureFile:@"crate.png" shininess:0 precision:Isgl3dTexturePrecisionMedium repeatX:YES repeatY:NO]; //CREATE ROOM IN 3D Isgl3dGLMesh * wallMesh = [Isgl3dPlane meshWithGeometry:_roomSide height:_wallHeight nx:10 ny:10]; //back wall Isgl3dMeshNode * backWall = [_container createNodeWithMesh:wallMesh andMaterial:wallMaterial]; backWall.position = iv3(0, 0, -_roomSide); //left wall Isgl3dMeshNode * leftWall = [_container createNodeWithMesh:wallMesh andMaterial:wallMaterial]; leftWall.position = iv3(-_roomSide*0.5, 0, -_roomSide*0.5); leftWall.rotationY = 90; //right wall Isgl3dMeshNode * rightWall = [_container createNodeWithMesh:wallMesh andMaterial:wallMaterial]; rightWall.position = iv3(_roomSide*0.5, 0, -_roomSide*0.5); rightWall.rotationY = -90; //ceiling Isgl3dGLMesh * ceilingMesh = [Isgl3dPlane meshWithGeometry:_roomSide height:_roomSide nx:10 ny:10]; Isgl3dMeshNode * ceiling = [_container createNodeWithMesh:ceilingMesh andMaterial:wallMaterial]; ceiling.position = iv3(0, _wallHeight*0.5, -_roomSide*0.5); ceiling.rotationX = 90; //make texture tile on the ground (2x horizontally, 2x vertically) Isgl3dUVMap * groundUVMap = [Isgl3dUVMap uvMapWithUA:0.0 vA:0.0 uB:2.0 vB:0.0 uC:0.0 vC:2.0]; Isgl3dPlane * groundMesh = [Isgl3dPlane meshWithGeometryAndUVMap:_roomSide height:_roomSide nx:2 ny:2 uvMap:groundUVMap]; Isgl3dMeshNode * ground = [_container createNodeWithMesh:groundMesh andMaterial:groundMaterial]; ground.position = iv3(0,-_wallHeight*0.5,-_roomSide*0.5); ground.rotationX = -90; //make ground plane receive TOUCH EVENTS ground.interactive = YES; [ground addEvent3DListener:self method:@selector(objectTouched:) forEventType:TOUCH_EVENT]; [ground addEvent3DListener:self method:@selector(objectReleased:) forEventType:RELEASE_EVENT]; [ground addEvent3DListener:self method:@selector(objectMoved:) forEventType:MOVE_EVENT]; //create crates _crates = [[NSMutableArray array] retain]; CGPoint pos; int i; Isgl3dCube * cubeMesh = [[Isgl3dCube alloc] initWithGeometry:_boxSide height:_boxSide depth:_boxSide nx:2 ny:2]; Isgl3dMeshNode * crate; for (i = 0; i < [cratePosition count]; i++) { pos = [[cratePosition objectAtIndex:i] CGPointValue]; crate = [_container createNodeWithMesh:cubeMesh andMaterial:crateMaterial]; crate.z = -1 * pos.y; crate.x = pos.x - _roomSide * 0.5; crate.y = -_wallHeight*0.5 + _boxSide*0.5; [_crates addObject:crate]; } //add player plane Isgl3dGLMesh * playerMesh = [Isgl3dPlane meshWithGeometry:_playerWidth height:_playerHeight nx:1 ny:1]; _player = [_container createNodeWithMesh:playerMesh andMaterial:[_frames_back objectAtIndex:0]]; _player.position = iv3(0, -_wallHeight*0.5 + _playerHeight*0.5, 0); _player.doubleSided = YES; //make it double sided so player can be flipped //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& BOX2D &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //create box2D elements _scale = 50; //room dimensions float b2RoomSide = 12 * _scale; float b2PlayerWidth = 1.5 * _scale; _speed = 3; _animate = false; _screenSize = [[Isgl3dDirector sharedInstance] windowRect].size; _center = CGPointMake(_screenSize.width*0.5, _screenSize.height*0.3); b2Vec2 gravity; gravity.Set(0.0f, 0.0f); bool doSleep = true; _world = new b2World(gravity, doSleep); _world->SetContinuousPhysics(true); int wallThickness = 4; //create player _b2Player = [self createBodyAt:CGPointMake(6*_scale, 1*_scale) withSize:CGSizeMake(b2PlayerWidth, 22) ofType:b2_dynamicBody]; _b2Player->SetFixedRotation(true); _b2Player->GetFixtureList()->SetDensity(5); for (i = 0; i < [cratePosition count]; i++) { pos = [[cratePosition objectAtIndex:i] CGPointValue]; [self makeBoxAt:CGPointMake(pos.x * _scale, pos.y * _scale) withIndex:i]; } //create walls b2Body * wall; //left wall wall = [self createBodyAt:CGPointMake(wallThickness*0.5, b2RoomSide*0.5) withSize:CGSizeMake(wallThickness, b2RoomSide) ofType:b2_staticBody]; //right wall wall = [self createBodyAt:CGPointMake(b2RoomSide+wallThickness*0.5, b2RoomSide*0.5) withSize:CGSizeMake(wallThickness, b2RoomSide) ofType:b2_staticBody]; //bottom wall wall = [self createBodyAt:CGPointMake(b2RoomSide*0.5, -wallThickness*0.5) withSize:CGSizeMake(b2RoomSide, wallThickness) ofType:b2_staticBody]; //top wall wall = [self createBodyAt:CGPointMake(b2RoomSide*0.5, b2RoomSide+wallThickness*0.5) withSize:CGSizeMake(b2RoomSide, wallThickness) ofType:b2_staticBody]; [self schedule:@selector(tick:)]; } return self; } //&&&&&&&&&&&&&&&&&&&& TOUCH EVENTS (On GROUND PLANE) &&&&&&&&&&&&& - (void) objectTouched:(Isgl3dEvent3D *)event { _animate = YES; UITouch * touch = [[event.touches allObjects] objectAtIndex:0]; CGPoint uiPoint = [touch locationInView:touch.view]; _touchLocation = [self convertUIPointToView:uiPoint]; } - (void) objectMoved:(Isgl3dEvent3D *)event { UITouch * touch = [[event.touches allObjects] objectAtIndex:0]; CGPoint uiPoint = [touch locationInView:touch.view]; _touchLocation = [self convertUIPointToView:uiPoint]; } - (void) objectReleased:(Isgl3dEvent3D *)event { _animate = NO; _frameIndex = 0; switch (_direction) { case MOVE_UP: _player.material = [_frames_back objectAtIndex:_frameIndex]; break; case MOVE_DOWN: _player.material = [_frames_front objectAtIndex:_frameIndex]; break; case MOVE_LEFT: _player.material = [_frames_side objectAtIndex:_frameIndex]; break; case MOVE_RIGHT: _player.material = [_frames_side objectAtIndex:_frameIndex]; break; } _player.y = -_wallHeight*0.5 + _playerHeight*0.5; } //MAIN LOOP ///////////////////////////// - (void) tick:(float)dt { _world->Step(dt, 8, 1); [self updatePlayer]; [self transFormObject:_b2Player threeD:_player andRotate:NO]; int len = [_crates count]; Isgl3dMeshNode * c; for (int i = 0; i < len; i++) { c = (Isgl3dMeshNode *) [_crates objectAtIndex:i]; [self transFormObject:_boxes2[i] threeD:c andRotate:YES]; } _container.x = -_player.x*0.4; _container.z = -_player.z*0.4; } //Update Box2D Player and Animate 3D player sprite -(void) updatePlayer { _b2Player->SetLinearVelocity(b2Vec2(0,0)); b2Vec2 playerVelocity = _b2Player->GetLinearVelocity(); if (_animate) { float diffx = _touchLocation.x - _center.x; float diffy = _touchLocation.y - _center.y; float rad = atan2f(diffy, diffx); int angle = 180 * rad / M_PI; if (angle < 360) angle += 360; if (angle > 360) angle -= 360; if (angle > 315 || angle < 45) { playerVelocity.x += _speed; _direction = MOVE_RIGHT; } else if (angle >= 45 && angle <= 135) { playerVelocity.y += _speed; _direction = MOVE_UP; } else if (angle > 135 && angle < 225) { playerVelocity.x -= _speed; _direction = MOVE_LEFT; } else { playerVelocity.y -= _speed; _direction = MOVE_DOWN; } _b2Player->SetLinearVelocity(playerVelocity); _animationCnt++; if (_animationCnt > 2) { _animationCnt = 0; _frameIndex++; if (_frameIndex == 4) _frameIndex = 1; switch (_direction) { case MOVE_UP: _player.material = [_frames_back objectAtIndex:_frameIndex]; break; case MOVE_DOWN: _player.material = [_frames_front objectAtIndex:_frameIndex]; break; case MOVE_LEFT: _player.rotationY = -180; _player.material = [_frames_side objectAtIndex:_frameIndex]; break; case MOVE_RIGHT: _player.rotationY = 0; _player.material = [_frames_side objectAtIndex:_frameIndex]; break; } if (_player.y == -_wallHeight*0.5 + _playerHeight*0.5) { _player.y = -_wallHeight*0.5 + _playerHeight*0.53; } else { _player.y = -_wallHeight*0.5 + _playerHeight*0.5; } } } } //Update 3D object based on Box2D object ///////////// -(void) transFormObject:(b2Body *) body1 threeD:(Isgl3dMeshNode *) body2 andRotate:(BOOL) rotate { if (body1 == NULL || body2 == NULL) return; b2Vec2 position = body1->GetPosition(); float angle = body1->GetAngle() * 180 / M_PI; body2.x = position.x * PTM_RATIO / _scale - _roomSide *0.5; body2.z = -1 * position.y * PTM_RATIO / _scale; if (rotate) body2.rotationY = angle; } //Box2D helper methods////////////////////////////////// -(void) makeBoxAt:(CGPoint) pos withIndex:(int)index { float boxSide = 1.4 * _scale; b2Body * body = [self createBodyAt:pos withSize:CGSizeMake(boxSide, boxSide) ofType:b2_dynamicBody]; body->GetFixtureList()->SetDensity(2); body->GetFixtureList()->SetFriction(0.3f); body->SetLinearDamping(5); body->SetTransform(body->GetPosition(), (float) random()/RAND_MAX); _boxes2[index] = body; } -(b2Body *) createBodyAt:(CGPoint) pos withSize:(CGSize) size ofType:(b2BodyType) type { b2BodyDef bodyDef; b2FixtureDef bodyFixture; bodyDef.position.Set(pos.x / PTM_RATIO, pos.y / PTM_RATIO); bodyDef.type= type; bodyDef.angularDamping = 10; bodyDef.allowSleep = false; b2PolygonShape bodyShape; bodyShape.SetAsBox(size.width*0.5 / PTM_RATIO, size.height*0.5 / PTM_RATIO); bodyFixture.shape = &bodyShape; bodyFixture.density = 1; b2Body * b = _world->CreateBody(&bodyDef); b->CreateFixture(&bodyFixture); return b; } - (void) dealloc { [_crates release]; [_frames_back release]; [_frames_front release]; [_frames_side release]; _crates = nil; delete _world; _world = NULL; [super dealloc]; } @end

