I'm trying to display some simple object with texture and enable spot light in my scene. I use GLKBaseEffect's texture & light.
When textures are disabled - I can see light effect (when I rotate object, it partly becomes dark, as expected). But when I enable textures (load them with GLKTextureInfo and bind in -(void)glkView:drawInRect:) - light effect disappears.
I've tried to search in Google and re-read Apple's documentation, but still can't find the answer.
UPDATE:
Here is the code, I use to setup light:
_effect.lightingType = GLKLightingTypePerPixel;
_effect.lightModelAmbientColor = GLKVector4Make(.3f, .3f, .3f, 1);
_effect.colorMaterialEnabled = GL_TRUE;
_effect.light0.enabled = GL_TRUE;
_effect.light0.spotCutoff = [[PRSettings instance] floatForKey:PRSettingsKeyLightSpotCutoff];
_effect.light0.spotExponent = [[PRSettings instance] floatForKey:PRSettingsKeyLightExponent];
_effect.light0.diffuseColor = _effect.light0.specularColor = GLKVector4Make(1, 1, 1, 1);
_effect.light0.position = GLKVector4Make(0, 0, 0, 1);
[_effect prepareToDraw];
If I call this code twice - the light will be disabled somehow. Even without textures - second call - I there is no light at all.
Simple answer... Should use _effect.texture2d0.envMode = GLKTextureEnvModeModulate; to mix input color (the light's one) and texture.
Several years ago, I wrote a small Cocoa/Obj-C game framework for OpenGL ES 1.1 and iPhone. This was back when iOS 3.x was popular. My OpenGL ES 1.1 / iOS 3.x implementation of this all worked fine. Time passed, and here we are now with iOS 5.1, OpenGL ES 2.0, ARC, blocks, and other things. I decided that it was high time to port the project over to more... modern standards.
EDIT: Solved one of the problems on my own - that of why it was crashing on the simulator. Sort of - I am now able to draw smaller models, but larger ones (like the test police car) still cause an EXC_BAD_ACCESS - even if that is the only, single call to glDrawElements. I was also able to fix drawing-multiple-meshes on the Simulator - however, I don't know if this will function on-device until tomorrow morning. (my 5.0 test device is my friend's iPhone, don't). So I guess the main question is, why are larger models causing an EXC_BAD_ACCESS on the simulator?
Original post below
However, in moving it up to 5.0, I've run into some OpenGL ES 2.0 errors - two of them, specifically, although they may possibly be related. The first of them is simple - if I try to render my model on a device (iPhone 4S running 5.0.1), it displays, but if I try to display it on the simulator (iPhone Simulator running 5.0), it throws an EXC_BAD_ACCESS on glDrawElements. The second, also simple. I cannot draw multiple meshes. When I draw the model as one big group (one vertex array/index array combo) it draws fine - but when I draw the model as multiple parts (eg, multiple calls to drawElements) it fails, and displays a big black screen - the blackness is not from the model being drawn (I have verified this, outlined below).
To sum it up before the much-more-detailed part, attempting to render my model on the simulator crashes
Caveat: It all works fine for small meshes. I have no problem drawing my small, statically-declared cube over and over, even on the simulator. When I say statically-declared, I mean a hard-coded const array of structs that gets bound and loaded into the vertex buffer and a const array of GLushorts bound and loaded into the index array.
Note: when I say 'model' I mean an overall model, possibly made up of multiple vertex and index buffers. In code, this means that a model simply holds an array of meshes or model-groups. A mesh or model-group is a sub-unit of a model, eg one contiguous piece of the model, has one vertex array and one index array, and stores the lengths of both as well. In the case of the model I've been using, the body of the car is one mesh, the windows another, the lights a third. All together, they make up the model.
The model I am using is a police car, has several thousand vertices and faces, and is split into multiple parts (body, lights, windows, etc) - the body is about 3000 faces, the windows about 100, the lights a bit less.
Here are some things to know:
My model is loading properly. I have verified this in two ways -
printing out the model vertices and manually inspecting them, and
displaying each model-group individually as outlined in 2). I'd post images, but 'reputation limit' and this being my first question, I can't. I have also re-built the model loader twice from scratch with no change, so I know the vertex and index buffers are in the correct order/format.
When I load the model as a single model-group (ie, one vertex
buffer/index buffer) it displays the whole model correctly. When I
load the model as multiple model-groups, and display any given
model-group individually, it displays correctly. When I try to draw
multiple model-groups (multiple calls to glDrawElements) the big
black screen happens.
The black screen is not because of the model being drawn. I
verified this by changing my fragment shader to draw every pixel
red no matter what. I always clear the color buffer to a medium-gray (I clear the depth buffer as well, obviously), but attempting to draw multiple meshes/model-groups results in a black screen. We know it is not the model simply obscuring the view because it is colored black instead of red. This occurs on the device, I do not know what would happen on the simulator as I cannot get it to draw.
My model will not draw in the simulator. It will not draw as either a single mesh/model-group, nor multiple mesh/model-groups. The application loads properly, but
attempting to draw a mesh/model-group results in an EXC_BAD_ACCESS in the
glDrawElements. The relevant parts of the backtrace are:
thread #1: tid = 0x1f03, 0x10b002b5, stop reason = EXC_BAD_ACCESS (code=1, address=0x94fd020)
frame #0: 0x10b002b5
frame #1: 0x09744392 GLEngine`gleDrawArraysOrElements_ExecCore + 883
frame #2: 0x09742a9b GLEngine`glDrawElements_ES2Exec + 505
frame #3: 0x00f43c3c OpenGLES`glDrawElements + 64
frame #4: 0x0001cb11 MochaARC`-[Mesh draw] + 177 at Mesh.m:81
EDIT: It consistently is able to draw smaller dynamically-created models (~100 faces) but the 3000 of the whole model
I was able to get it to render a much-smaller, less-complicated, but still dynamically loaded, model consisting of 192 faces / 576 vertices. I was able to display it both as a single vertex and index buffer, as well as split up into parts and rendered as multiple smaller vertex and index buffers. Attempting to draw the single-mesh model in the simulator resulted in the EXC_BAD_ACCESS still being thrown, but only on the first frame. If I force it to continue, it displays a very screwed up model, and then every frame after that, it displayed 100% fine exactly as it ought to have.
My shaders are not in error. They compile and display correctly when I use a small, statically declared vertex buffer. However, for completeness I will post them at the bottom.
My code is as follows:
Render loop:
glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//muShader is a subclass of a shader-handler I've written that tracks the active shader
//and handles attributes/uniforms
//[muShader use] just does glUseProgram(muShader.program); then
//disables the previous shader's attributes (if needed) and then
//activates its own attributes - in this case:
//it does:
// glEnableVertexAttribArray(self.position);
// glEnableVertexAttribArray(self.uv);
//where position and uv are handles to the position and texture coordinate attributes
[self.muShader use];
GLKMatrix4 model = GLKMatrix4MakeRotation(GLKMathDegreesToRadians(_rotation), 0, 1, 0);
GLKMatrix4 world = GLKMatrix4Identity;
GLKMatrix4 mvp = GLKMatrix4Multiply(_camera.projection, _camera.view);
mvp = GLKMatrix4Multiply(mvp,world);
mvp = GLKMatrix4Multiply(mvp, model);
//muShader.modelViewProjection is a handle to the shader's model-view-projection matrix uniform
glUniformMatrix4fv(self.muShader.modelViewProjection,1,0,mvp.m);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, self.policeTextureID);
//ditto on muShader.texture
glUniform1i(self.muShader.texture, 0);
for(int i=0; i < self.policeModel.count; i++)
{
//I'll expand muShader readyForFormat after this
[self.muShader readyForFormat:ModelVertexFormat];
//I'll expand mesh draw after this
[[self.policeModel meshAtIndex:i] draw];
}
muShader stuff
muShader binding attributes and uniforms
I won't post the whole muShader's class, it is unnecessary, suffice to say that it works or else it'd not display anything at all, ever.
//here is where we bind the attribute locations when the shader is created
-(void)bindAttributeLocations
{
_position = glGetAttribLocation(self.program, "position");
_uv = glGetAttribLocation(self.program, "uv");
}
//ditto for uniforms
-(void)bindUniformLocations
{
_modelViewProjection = glGetUniformLocation(self.program, "modelViewProjection");
_texture = glGetUniformLocation(self.program, "texture");
}
muShader readyForFormat
-(void)readyForFormat:(VertexFormat)vertexFormat
{
switch (vertexFormat)
{
//... extra vertex formats removed for brevity
case ModelVertexFormat:
//ModelVertex is a struct, with the following definition:
//typedef struct{
// GLKVector4 position;
// GLKVector4 uv;
// GLKVector4 normal;
//}ModelVertex;
glVertexAttribPointer(_position, 3, GL_FLOAT, GL_FALSE, sizeof(ModelVertex), BUFFER_OFFSET(0));
glVertexAttribPointer(_uv, 3, GL_FLOAT, GL_FALSE, sizeof(ModelVertex), BUFFER_OFFSET(16));
break;
//... extra vertex formats removed for brevity
}
}
Mesh stuff
setting up the vertex/index buffers
//this is how I set/create the vertex buffer for a mesh/model-group
//vertices is a c-array of ModelVertex structs
// created with malloc(count * sizeof(ModelVertex))
// and freed using free(vertices) - after setVertices is called, of course
-(void)setVertices:(ModelVertex *)vertices count:(GLushort)count
{
//frees previous data if necessary
[self freeVertices];
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(ModelVertex) * count, vertices, GL_STATIC_DRAW);
_vertexCount = count;
}
//this is how I set/create the index buffer for a mesh/model-group
//indices is a c-array of GLushort,
// created with malloc(count * sizeof(GLushort);
// and freed using free(vertices) - after setVertices is called, of course
-(void)setIndices:(GLushort *)indices count:(GLushort)count
{
[self freeIndices];
glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * count, indices, GL_STATIC_DRAW);
_indexCount = count;
}
mesh draw
//vertexBuffer and indexBuffer are handles to a vertex/index buffer
//I have verified that they are loaded properly
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glDrawElements(GL_TRIANGLES, _indexCount, GL_UNSIGNED_SHORT, 0);
Shader stuff
Vertex Shader
attribute highp vec4 position;
attribute lowp vec3 uv;
varying lowp vec3 fragmentUV;
uniform highp mat4 modelViewProjection;
uniform lowp sampler2D texture;
void main()
{
fragmentUV = uv;
gl_Position = modelViewProjection * position;
}
Fragment shader
varying lowp vec3 fragmentUV;
uniform highp mat4 modelViewProjection;
uniform lowp sampler2D texture;
void main()
{
gl_FragColor = texture2D(texture,fragmentUV.xy);
//used below instead to test the aforementioned black screen by setting
//every pixel of the model being drawn to red
//the screen stayed black, so the model wasn't covering the whole screen or anything
//gl_FragColor = vec4(1,0,0,1);
}
Answered it myself, when using multiple buffer objects, glEnableVertexAttribArray has to be called for every time you bind the vertex/index buffer object, rather than simply once per frame (per shader). This was the cause of all of the problems, including the simulator crashing.
Closed.
I'm new here so i hope you can help me.
I am following a tutorial on making simple cocos2d game
Ray Wenderlich's Tutorial
I implemented it on another game a jumping one like doodle jump.
in the said tutorial the monsters/targets are moving freely coming from the right to the left side of the screen. when i implement it on my app the monsters are like flying from left to right. What if i want the monsters to stand on the platforms just like the one on doodle jump? what particular things will i do?
PS:i tried some other things on google but none works
Here is the code of the monsters/targets:
- (void)initPlatforms {
// NSLog(#"initPlatforms");
currentPlatformTag = kPlatformsStartTag;
while(currentPlatformTag < kPlatformsStartTag + kNumPlatforms) {
[self initPlatform];
currentPlatformTag++;
}
[self resetPlatforms];
}
- (void)initPlatform {
CGRect rect;
switch(random()%2) {
case 0: rect = CGRectMake(608,64,102,36); break;
case 1: rect = CGRectMake(608,128,90,32); break;
}
AtlasSpriteManager *spriteManager = (AtlasSpriteManager*)[self getChildByTag:kSpriteManager];
AtlasSprite *platform = [AtlasSprite spriteWithRect:rect spriteManager:spriteManager];
[spriteManager addChild:platform z:3 tag:currentPlatformTag];
}
-(void)addTarget {
Sprite *target = [Sprite spriteWithFile:#"komodo.png"];
target.position = ccp(300,200);
[self addChild:target];
CGSize winSize = [[Director sharedDirector]winSize];
int minX = target.contentSize.height/2;
int maxX = winSize.height -target.contentSize.height/2;
int rangeX = maxX - minX;
int actualX = (arc4random() % rangeX) +minX;
int minDuration = 2.0;
int maxDuration = 4.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
id actionMove = [MoveTo actionWithDuration:actualDuration position:ccp(-target.contentSize.width,actualX)];
id actionMoveDone = [CallFuncN actionWithTarget:self selector:#selector(spriteMoveFinished:)];
[target runAction:[Sequence actions:actionMove, actionMoveDone,nil]];
target.tag = 1;
[_targets addObject:target];
}
Thanks to those who will help... you are so nice.
This is a pretty broad question unfortunately, which makes it difficult to answer in any definitive terms. If you are hoping to create actual platforms that can be bounced on (in a doodle jump manner) you are going to need to implement collision detection between the Monsters and the Platform ccNodes. There are numerous tutorials online for cocos2d collision detection, both simple implementation and the more advanced box 2d/chipmunk based solutions.
If you are looking to clone doodle jump fairly closely, there is an open source version of a clone available on github here - though I've not actually looked at the code.
Finally, if you mean that you simply want to restrict the movement of the monsters to a particular area of the screen (so they don't keep running off the edge) you just need to position the target to an area on the screen and alter theccAction so that the ccMoveTo uses the left most point of the 'platform' as the furthest point left it can move to and the right most point as the furthest right. (I'll confess I've not played Doodle Jump so have no idea what the enemies actually do).
If the enemies run back and forth across the platform you should look into using ccRepeatForever on your movement sequence and have two destination positions in the CCSequence : one that moves the monster to the left of the platform, the other to move it to the right.
Additional Info
Ok, I see what you are trying to do. This should get you started:
Platforms are created in initPlatforms. This calls initPlatform a number of times. This grabs an image from the AtlasSprite for the platform, creates a ccSprite for each platform and assigns it a unique tag.
Then, in - (void)step:(ccTime)dt it loops through all the platforms and moves them to their correct location based on how far the bird has moved:
for(t; t < kPlatformsStartTag + kNumPlatforms; t++) {
AtlasSprite *platform = (AtlasSprite*)[spriteManager getChildByTag:t];
//etc...
So, the bit you are waiting for:
If you want to add a monster to these platforms, you will have to follow a similar pattern. To get started try something like this (You will want to have a cleaner design than this though but it should put you on the right track)
in initPlatform add the following to the end of the function
// add a monster sprite
AtlasSprite *monster = [AtlasSprite spriteWithRect:CGRectMake(608,128,64,64) spriteManager:spriteManager];
[spriteManager addChild:monster z:3 tag:currentPlatformTag + 1000];
(I've just grabbed an image from the existing Atlas. You could replace the above with your actual 'Monster' sprite object. Notice I add 1000 to thecurrentPlatformTag. This is just for testing; you should have a monsterTag implementation eventually.
So now every platform has a 'monster' (Again, you will only want to target random platforms)
so we need to update the positions for the monsters.
In - (void)step:(ccTime)dt directly after you get the current platform
AtlasSprite *platform = (AtlasSprite*)[spriteManager getChildByTag:t];
You now also need to get the current monster (remembering to use the updated tag value we created for 'monsters':
AtlasSprite *monster = (AtlasSprite*)[spriteManager getChildByTag:t + 1000];
Then, a few lines below where we reposition the platform we will need to reposition the monster
platform.position = pos;
// We update the monster and set it a 32 pixels above the platform:
monster.position = ccp(pos.x, pos.y + 32);
So now each platform has a monster on it whose y position moves with the the platforms :-)
Hope this helps
I'm trying to make a game where the user is supposed to drag a sprite up and down on the screen, avoiding incoming obstacles. The last answer here helped me to drag the sprite around on the screen, but I want to set a maximum speed the sprite can be moved (and hopefully with a natural-looking acceleration/deceleration), so it doesn't get too easy to avoid the objects.
Does anybody know how I can modify the code to achieve this, or is there another way to to it?
Thanks :)
You'll need to maintain a CGPoint destinationPosition variable which is the location of your finger and use an update loop to modify it's position:
-(void) update:(ccTime) dt
{
CGPoint currentPosition = draggableObject.position.x;
if (destination.x != currentPosition.x)
{
currentPosition.x += (destination.x - currentPosition.x) / 5.0f; // This 5.0f is how fast you want the object to move to it's destination
}
if (destination.y != currentPosition.y)
{
currentPosition.y += (destination.y - currentPosition.y) / 5.0f;
}
draggableObject.postion = currentPosition;
}
In the ifs, you might want to check if the objects are close to each other, rather than exactly the same number to allow for rounding errors.
You just need to have an if statement in whatever schedule updater you are using, like time, or touches, or whatever.
I'm presuming you have x/y velocities? Just inside your update statement, wherever your acceleration is -
if(acceleration.x > 20){
acceleration.x = 20;
}
if(acceleration.y > 20){
acceleration.y = 20;
}
i want to determine if the sprite is in the screen or not in cocos2d.
am using the code some thing like these.
CGSize winSize = [CCDirector sharedDirector].winSize;
if (_SmallBlueAlien1.position.x> 0 || _SmallBlueAlien1.position.x > winSize.width || _SmallBlueAlien1.position.y> 0 || _SmallBlueAlien1.position.y > winSize.height)
{
//Sprite is not in the screen)
}
but not working properly. were am mistaking.
correct me
Unless you changed the anchor point of the sprite this is only testing if half of the sprite is on the screen. To fix this you want to check if
_SmallBlueAlien1.position.x > [_SmallBlueAlien1 contentSize].texture.width / 2;
You can follow this process for all the other interactions.
//Edit
As phix23 noted this does not account for rotation or scale but should work if you are doing neither of those.
regardless of the semantics of 'position' in coco, your '>' should be '<' for both x and y, assuming your interpretation of the .position property holds. It is likely however that the 'sprite'.position is in reference to an enclosing object, thus even when your test is corrected, it may still not give you what you want to know ('visible on screen').