If we were to manually define these shapes and transformations for each object, it'll quickly get messy. In this chapter we'll define a rendering class that allows us to render a large amount of unique sprites with a minimal amount of code. This way, we're abstracting the gameplay code from the gritty OpenGL rendering code as is commonly done in larger projects.
First, we have to set up a proper projection matrix though. We know from the coordinate systems chapter that a projection matrix converts all view-space coordinates to clip-space and then to normalized device coordinates. By generating the appropriate projection matrix we can work with different coordinates that are easier to work with, compared to directly specifying all coordinates as normalized device coordinates. We don't need any perspective applied to the coordinates, since the game is entirely in 2D, so an orthographic projection matrix would suit the rendering quite well.
Because an orthographic projection matrix directly transforms all coordinates to normalized device coordinates, we can choose to specify the world coordinates as screen coordinates by defining the projection matrix as follows:.
The first four arguments specify in order the left, right, bottom, and top part of the projection frustum. This projection matrix transforms all x coordinates between 0 and to -1 and 1 , and all y coordinates between 0 and to -1 and 1.
Here we specified that the top of the frustum has a y coordinate of 0 , while the bottom has a y coordinate of The result is that the top-left coordinate of the scene will be at 0,0 and the bottom-right part of the screen is at coordinate , , just like screen coordinates; the world-space coordinates directly correspond to the resulting pixel coordinates.
This allows us to specify all vertex coordinates equal to the pixel coordinates they end up in on the screen, which is rather intuitive for 2D games. Rendering an actual sprite shouldn't be too complicated. We create a textured quad that we can transform with a model matrix, after which we project it using the previously defined orthographic projection matrix. Note that we store both the position and texture-coordinate data in a single vec4 variable.
Because both the position and texture coordinates contain two floats, we can combine them in a single vertex attribute. The fragment shader is relatively straightforward as well. We take a texture and a color vector that both affect the final color of the fragment. By having a uniform color vector, we can easily change the color of sprites from the game-code:. The ball keeps this up, until it eventually finds a gap again. This is logically where the game obtained its name from, since the ball has to break out.
We're going to take this classic arcade game as the basis of a 2D game that we'll completely implement with OpenGL. This version of Breakout will render its graphics on the GPU which gives us the ability to enhance the classical Breakout game with some nice extra features.
To get you excited you can see what the game will look like after you've finished these chapters:. These chapters will combine a large number of concepts from previous chapters and demonstrate how they can work together as a whole. Therefore, it is important to have at least finished the Getting started chapters before working your way through these series. Also, several chapters will require concepts from other chapters Framebuffers for example from the Advanced OpenGL section so where necessary, the required chapters are listed.
If you believe you're ready to get your hands dirty then move on to the next chapter. I find it hard to think about. Luckily, this is quite easy to fix! Open SGGSprite. Here we just shift the geometry by half the width and height to the lower left, so that the position matches up to the center of the sprite.
Note: With some slight modifications, you can modify this code to allow you to set an anchor point on a sprite-by-sprite basis just like you can in Cocos2D. If you look at CCNode. In Cocos2D we have these wonderful things called actions that we can use to easily move sprites over time. We will simply give each sprite a new property called moveVelocity.
It will be a vector representing the amount a sprite should move in 1 second. The update method will be called with the amount of time that has passed since the last update, in seconds. So to figure out how much we should move the sprite this frame in points , we multiply the move velocity points per second by the delta time seconds. Here we create an array of children i. This makes it easy to render and update all sprites just by looping through the list of children.
We give the player an initial move velocity — 50 points up and 50 points to the right, every second. Instead, we want to add some moving targets into our scene for our ninja to combat. Here we create a new target and add it to the list of children so it will be rendered and updated each frame. We then figure out where to position the target when it spawns. We place it offscreen to the right, at a random spot between the bottom and top of the screen.
Then we figure out how fast it should move. We pick a random value between Here is an example project with all of the code from the tutorial so far. You have drawn sprites to the screen, positioned them where you like, and even made them move.
The raywenderlich. Get a weekly digest of our tutorials and courses, and receive a free in-depth email course as a bonus! Learn iOS, Swift, Android, Kotlin, Dart, Flutter and more with the largest and highest-quality catalog of video courses and books on the internet.
Ray is part of a great team - the raywenderlich. A raywenderlich. Why Use GLKit? Core Concepts Archive. Sign up now Website. All videos. All books. One low price. Learn more.
0コメント