ne0_kamen

Member

110

371 Neutral

• Rank
Member
1. What is the best 3D game to make first?

I second this suggestion.
2. Chris Crawford's Dragon Speech translation

This is slightly off topic, but for anyone who haven't seen this I strongly recommend watching the lecture. The passion Mr. Crawford puts into the presentation is mind boggling.   It would be interesting topic of conversation to discuss whether his conclusion that interactive storytelling is (was) the future is really true. From a business point of view, I think all his attempts to create such games are failures. However, I would classify a recent game such as Beyond Two Souls as Interactive story telling. Maybe not in the way Chris Crawford envisioned, but similar. Is there a whole new genre of games, which potential is not fully discovered yet?
3. Having problems with collision detection in 2d platformer

mapxoff/mapyoff are my camera variables. They move along with my player and yes the position of the rings depend on them. If they are not in range of my camera, they don't render, heres the code in case: //update the map scroll position //camera coordinates mapxoff = player->x + player->width/2 - WIDTH/2 + 10; mapyoff = player->y + player->height/2 - HEIGHT/2 + 10; //Avoid moving beyond the map edge if(mapxoff < 0) mapxoff = 0; if(mapxoff > mapwidth*mapblockwidth - WIDTH) mapxoff = mapwidth*mapblockwidth - WIDTH; if(mapyoff < 0) mapyoff = 0; if(mapyoff > mapheight*mapblockheight - HEIGHT) mapyoff = mapheight*mapblockheight - HEIGHT;   You should have everything in the same coordinate system. For collision detection, you don't need to "scroll" the world using camera offset, just use the object's world coordinates like this :                //find the center of the player             x = player->x + player->width/2;             y = player->y + player->height/2;             //get the rings bounding rectangle             x1 = rings[n]->x ;             y1 = rings[n]->y;             x2 = x1 + rings[n]->width;             y2 = y1 + rings[n]->height;   Hope this helps, Kamen
4. Half life : a game that changed the fps genre

Hello, Recently, looking for new information on Half-life 3 or episode 3 I stumbled upon this article/video : [url="http://www.gamespot.com/news/half-life-3-wait-explained-6372687"]http://www.gamespot....plained-6372687[/url] [media]http://www.youtube.com/watch?feature=player_embedded&v=6VofXcw8AJQ[/media] While the article doesn't provide much information about the upcoming games of the franchise, I found the video very interesting - it summarizes very nicely what I think was great about half life 1/2 and stuff that's missing in today's fps games. The level design, the story and characters, the original weapons, the scripted events of dying scientists, the g-man encounters, the fun and replay value of the games... It just seems it isn't there in modern FPS games. Admittedly, I haven't played any of the latest shooters (my last one was Crysis 1), so I want to ask what do you think about this? Are the developers responsible for not putting enough love/work/passion into the product or is it just that today's gamers don't need games like Half-life anymore?
5. Haiku update

As always, great work!!
6. Tetris in Ruby

Hello, My exams are over (finally). One of the courses I took this semester was introduction to the Ruby language. For the final exam, we had to make some project of moderate complexity. The result was like 90% web apps (written using Rails), several console apps and several games (most of which were chess simulators, they seem to be beloved among the academia). So I figured I would do a very basic game I never did before - Tetris. Ruby is a really cool language for prototyping and its amazing how much time it could save you with its "blocks passed as arguments" and extensive Enumerable class methods. For the graphics front-end/window creation and sound, I used gosu. Its amazingly simple and fast enough for the job. It took me a few hours to program the whole thing (+unit tests). The result is not bad, but apparently not good enough (I got a 4 out of 6 score). The biggest remark I got from my lecturer was that my rendering and game logic was too tightly coupled together. Which is true, of course. However, I believe that decoupling them would complicate things quite a bit (and thus make the project bigger, andwould take me more time). I just don't get why the professors always think an over-engineered, but "extensible and maintainable" solution isbetter than a simple one. Its not like I'm going to bring my course work into a full blown product. Source require 'gosu' class Block attr_accessor :falling attr_accessor :x, :y, :width, :height, :color @@image = nil def initialize(game) # Image is loaded only once for all blocks if @@image == nil @@image = Gosu::Image.new(game, "block.png", false) end @x = 0 @y = 0 @width = @@image.width; @height = @@image.height @game = game @color = 0xffffffff end def draw @@image.draw(@x, @y, 0, 1, 1, @color) end def collide(block) # Two blocks collide only when they are at the same position, since the world is a grid return (block.x == @x && block.y == @y) end def collide_with_other_blocks @game.blocks.each do |block| if collide(block) return block end end nil end end class Shape attr_accessor :rotation def initialize(game) @game = game @last_fall_update = Gosu::milliseconds @last_move_update = Gosu::milliseconds @blocks = [Block.new(game), Block.new(game), Block.new(game), Block.new(game) ] @x = @y = 0 @falling = true # Rotation is done about this block @rotation_block = @blocks[1] # How many rotations we can do before a full cycle? @rotation_cycle = 1 # Current rotation state @rotation = 0 end def apply_rotation # Each rotation is a 90 degree in the clockwise direction if @rotation_block != nil (1..@rotation.modulo(@rotation_cycle)).each do |i| @blocks.each do |block| old_x = block.x old_y = block.y block.x = @rotation_block.x + (@rotation_block.y - old_y) block.y = @rotation_block.y - (@rotation_block.x - old_x) end end end end # Note that the following function is defined properly only when the object is unrotated # Otherwise the line of symmetry will be misplaced and wrong results will be produced def reverse # Mirror the shape by the y axis, effectively creating shape counterparts such as 'L' and 'J' center = (get_bounds[2] + get_bounds[0]) / 2.0 @blocks.each do |block| block.x = 2*center - block.x - @game.block_width end end def get_bounds # Go throug all blocks to find the bounds of this shape x_min = [] y_min = [] x_max = [] y_max = [] @blocks.each do |block| x_min @game.width ) return true end if ( bounds[0] < 0 ) return true end return false end end class ShapeI < Shape def initialize(game) super(game) @rotation_block = @blocks[1] @rotation_cycle = 2 end def get_blocks @blocks[0].x = @x @blocks[1].x = @x @blocks[2].x = @x @blocks[3].x = @x @blocks[0].y = @y @blocks[1].y = @blocks[0].y + @blocks[0].height @blocks[2].y = @blocks[1].y + @blocks[1].height @blocks[3].y = @blocks[2].y + @blocks[2].height apply_rotation @blocks.each { |block| block.color = 0xffb2ffff } end end class ShapeL < Shape def initialize(game) super(game) @rotation_block = @blocks[1] @rotation_cycle = 4 end def get_blocks @blocks[0].x = @x @blocks[1].x = @x @blocks[2].x = @x @blocks[3].x = @x + @game.block_width @blocks[0].y = @y @blocks[1].y = @blocks[0].y + @game.block_height @blocks[2].y = @blocks[1].y + @game.block_height @blocks[3].y = @blocks[2].y apply_rotation @blocks.each { |block| block.color = 0xffff7f00 } end end class ShapeJ < ShapeL def get_blocks # Reverse will reverse also the direction of rotation that's applied in apply_rotation # This will temporary disable rotation in the super method, so we can handle the rotation here after the reverse old_rotation = @rotation @rotation = 0 super reverse @rotation = old_rotation apply_rotation @blocks.each { |block| block.color = 0xff0000ff} end end class ShapeCube < Shape def get_blocks @blocks[0].x = @x @blocks[1].x = @x @blocks[2].x = @x + @game.block_width @blocks[3].x = @x + @game.block_width @blocks[0].y = @y @blocks[1].y = @blocks[0].y + @game.block_height @blocks[2].y = @blocks[0].y @blocks[3].y = @blocks[2].y + @game.block_height @blocks.each { |block| block.color = 0xffffff00} end end class ShapeZ < Shape def initialize(game) super(game) @rotation_block = @blocks[1] @rotation_cycle = 2 end def get_blocks @blocks[0].x = @x @blocks[1].x = @x + @game.block_width @blocks[2].x = @x + @game.block_width @blocks[3].x = @x + @game.block_width*2 @blocks[0].y = @y @blocks[1].y = @y @blocks[2].y = @y + @game.block_height @blocks[3].y = @y + @game.block_height apply_rotation @blocks.each { |block| block.color = 0xffff0000} end end class ShapeS < ShapeZ def get_blocks # Reverse will reverse also the direction of rotation that's applied in apply_rotation # This will temporary disable rotation in the super method, so we can handle the rotation here after the reverse old_rotation = @rotation @rotation = 0 super reverse @rotation = old_rotation apply_rotation @blocks.each { |block| block.color = 0xff00ff00} end end class ShapeT < Shape def initialize(game) super(game) @rotation_block = @blocks[1] @rotation_cycle = 4 end def get_blocks @blocks[0].x = @x @blocks[1].x = @x + @game.block_width @blocks[2].x = @x + @game.block_width*2 @blocks[3].x = @x + @game.block_width @blocks[0].y = @y @blocks[1].y = @y @blocks[2].y = @y @blocks[3].y = @y + @game.block_height apply_rotation @blocks.each { |block| block.color = 0xffff00ff} end end class TetrisGameWindow < Gosu::Window attr_accessor :blocks attr_reader :block_height, :block_width attr_reader :level attr_reader :falling_shape STATE_PLAY = 1 STATE_GAMEOVER = 2 def initialize super(320, 640, false) @block_width = 32 @block_height = 32 @blocks = [] @state = STATE_PLAY spawn_next_shape @lines_cleared = 0 @level = 0 self.caption = "Tetris : #{@lines_cleared} lines" @song = Gosu::Song.new("TetrisB_8bit.ogg") end def update if ( @state == STATE_PLAY ) if ( @falling_shape.collide ) @state = STATE_GAMEOVER else @falling_shape.update end @level = @lines_cleared / 10 self.caption = "Tetris : #{@lines_cleared} lines" else if ( button_down?(Gosu::KbSpace) ) @blocks = [] @falling_shape = nil @level = 0 @lines_cleared = 0 spawn_next_shape @state = STATE_PLAY end end if ( button_down?(Gosu::KbEscape) ) close end @song.play(true) end def draw @blocks.each { |block| block.draw } @falling_shape.draw if @state == STATE_GAMEOVER text = Gosu::Image.from_text(self, "Game Over", "Arial", 40) text.draw(width/2 - 90, height/2 - 20, 0, 1, 1) end end def button_down(id) # Rotate shape when space is pressed if ( id == Gosu::KbSpace && @falling_shape != nil ) @falling_shape.rotation += 1 if ( @falling_shape.collide ) @falling_shape.rotation -= 1 end end end def spawn_next_shape # Spawn a random shape and add the current falling shape' blocks to the "static" blocks list if (@falling_shape != nil ) @blocks += @falling_shape.get_blocks end generator = Random.new shapes = [ShapeI.new(self), ShapeL.new(self), ShapeJ.new(self), ShapeCube.new(self), ShapeZ.new(self), ShapeT.new(self), ShapeS.new(self)] shape = generator.rand(0..(shapes.length-1)) @falling_shape = shapes[shape] end def line_complete(y) # Important is that the screen resolution should be divisable by the block_width, otherwise there would be gap # If the count of blocks at a line is equal to the max possible blocks for any line - the line is complete i = @blocks.count{|item| item.y == y} if ( i == width / block_width ) return true; end return false; end def delete_lines_of( shape ) # Go through each block of the shape and check if the lines they are on are complete deleted_lines = [] shape.get_blocks.each do |block| if ( line_complete(block.y) ) deleted_lines.push(block.y) @blocks = @blocks.delete_if { |item| item.y == block.y } end end @lines_cleared += deleted_lines.length # This applies the standard gravity found in classic Tetris games - all blocks go down by the # amount of lines cleared @blocks.each do |block| i = deleted_lines.count{ |y| y > block.y } block.y += i*block_height end end end # This global prevents creation of the window and start of the simulation when we are doing testing if ( !$testing ) window = TetrisGameWindow.new window.show end And unit tests (they were required)$testing = true require "./tetris.rb" require "test/unit" class TestTetris < Test::Unit::TestCase def setup @game = TetrisGameWindow.new @w = @game.block_width @h = @game.block_height end def test_shapes_construction assert_equal(4, ShapeI.new(@game).get_blocks.length, "ShapeI must be constructed of 4 blocks") assert_equal(4, ShapeT.new(@game).get_blocks.length, "ShapeT must be constructed of 4 blocks") assert_equal(4, ShapeJ.new(@game).get_blocks.length, "ShapeJ must be constructed of 4 blocks") assert_equal(4, ShapeZ.new(@game).get_blocks.length, "ShapeZ must be constructed of 4 blocks") assert_equal(4, ShapeCube.new(@game).get_blocks.length, "ShapeO must be constructed of 4 blocks") assert_equal(4, ShapeS.new(@game).get_blocks.length, "ShapeS must be constructed of 4 blocks") assert_equal(4, ShapeL.new(@game).get_blocks.length, "ShapeL must be constructed of 4 blocks") assert_not_equal(nil, @game.falling_shape, "Falling shape shoudn't be nil") end def test_shapes_rotation shape = ShapeI.new(@game) shape.rotation = 1 assert(shape_contain_block(shape, -2*@w, @h), "Rotation of I failed!") assert(shape_contain_block(shape, -@w, @h), "Rotation of I failed!") assert(shape_contain_block(shape, 0, @h), "Rotation of I failed!") assert(shape_contain_block(shape, @w, @h), "Rotation of I failed!") shape = ShapeL.new(@game) shape.rotation = 2 assert(shape_contain_block(shape, -@w, 0), "Rotation of L failed!") assert(shape_contain_block(shape, 0, 0), "Rotation of L failed!") assert(shape_contain_block(shape, 0, @h), "Rotation of L failed!") assert(shape_contain_block(shape, 0, 2*@h), "Rotation of L failed!") shape = ShapeJ.new(@game) shape.rotation = 2 assert(shape_contain_block(shape, 2*@w, 0), "Rotation of J failed!") assert(shape_contain_block(shape, @w, 0), "Rotation of J failed!") assert(shape_contain_block(shape, @w, @h), "Rotation of J failed!") assert(shape_contain_block(shape, @w, 2*@h), "Rotation of J failed!") shape = ShapeZ.new(@game) shape.rotation = 2 assert(shape_contain_block(shape, 0, 0), "Rotation of Z failed!") assert(shape_contain_block(shape, @w, 0), "Rotation of Z failed!") assert(shape_contain_block(shape, @w, @h), "Rotation of Z failed!") assert(shape_contain_block(shape, 2*@w, @h), "Rotation of Z failed!") shape = ShapeS.new(@game) shape.rotation = 1 assert(shape_contain_block(shape, 0, -@h), "Rotation of S failed!") assert(shape_contain_block(shape, 0, 0), "Rotation of S failed!") assert(shape_contain_block(shape, @w, 0), "Rotation of S failed!") assert(shape_contain_block(shape, @w, @h), "Rotation of S failed!") shape = ShapeT.new(@game) shape.rotation = 3 assert(shape_contain_block(shape, @w, -@h), "Rotation of T failed!") assert(shape_contain_block(shape, @w, 0), "Rotation of T failed!") assert(shape_contain_block(shape, 2*@w, 0), "Rotation of T failed!") assert(shape_contain_block(shape, @w, @h), "Rotation of T failed!") end def test_block_collision block1 = Block.new(@game) block2 = Block.new(@game) block2.x = @w block2.y = 0 assert_equal(false, block1.collide(block2), "Blocks should not collide") block2.x = 0 block2.y = 0 assert_equal(true, block1.collide(block2), "Blocks should collide") end def test_line_complete (0.. (@game.width/@w - 1)).each do |i| add_block(i*@w, 0) end (0.. (@game.width/@w - 2)).each do |i| add_block(i*@w, @h) end assert_equal(true, @game.line_complete(0), "Line should be complete") assert_equal(false, @game.line_complete(@h), "Line should not be complete") shapeI = ShapeI.new(@game) @game.delete_lines_of(shapeI) (0.. (@game.width/@w - 1)).each do |i| assert_equal(false, contain_block(@game.blocks, i*@w, 0), "Line 0 should be deleted ") end end def add_block(x,y) block = Block.new(@game) block.x = x block.y = y @game.blocks If you run the game in the ruby 1.9 interpreter, be sure to install gosu : gem install gosu
7. Realtime raytracing with OpenCL II

I've done some research, and you are correct - every single source seems to point out that OpenCL does not support recursion. However, in my code recursion definitely works (as seen from the reflection and refraction in the images). My guess is either the latest version of OpenCL recently changed that or more likely the ATI drivers automatically emulates the recursion for you. I'm pretty sure there is performance overhead in doing so, and even more so - the recursion rays are not computed in parallel . So regardless if OpenCL support recursion or not, you probably should use non-recursive raytracing for optimum speed.
8. Math Behind Look At Matrix 4x4

I think I know where is the problem. First, you are "adding" and "subtracting" the target's x,y,z to the LookAtMatrix's translation vector. This is doing nothing. You should create new translation matrices with these offsets and multiply the LookAtMatrix by them(as I did in the formula). Second, the "old" transformation (Matrix4f transform(LookAtMatrix) ) is screwing you. There would be rotations and translations in this "old" matrix and they will affect what you are trying to do (I think). Now the first problem is easy to solve. The second is harder. I think the correct order is this : [CODE] // Store our old global translation Vector3 lookAtMatrixTranslation(LookAtMatrix[12],LookAtMatrix[13],LookAtMatrix[14]); // We need just the rotation part of the lookAtMatrix Matrix4f lookAtMatrixRotation(LookAtMatrix); lookAtMatrixRotation[12] = lookAtMatrixRotation[13] = lookAtMatrixRotation[14] = 0; // Here we can add the offsets directly (or use SetTranslation), because transform is the Identity matrix Matrix4f transform = Matrix4f().SetTranslation(target); // Multiply it by the old rotation - note that the old rotation does not affect the current translation transform = transform*lookAtMatrixRotation; // Not sure if you need to create new matrices here, depends on the realization of RotateAngle transform.RotateAngle(mouse_x, upVector); transform.RotateAngle(mouse_y, rightVector); // Finally translate back, but create new matrix and multiply by it // Also add the previous (global) translation transform = transform*Matrix4f().SetTranslation(-target+lookAtMatrixTranslation); LocalTranslation = Vector3(transform[12], transform[13], transform[14]); LocalRotation.SetFromMatrix(transform); [/CODE] This is very untested, so I may be missing something crucial. I'm very sure that you need to create new translation matrices and multiply by them, but not sure how to handle the old translation/rotation. Perhaps somebody else can help there
9. Math Behind Look At Matrix 4x4

[size=3]So you can't use the formula because you forced the order of rotation/scalation/translation multiplication? This is possible, but I think forcing the order is not a good idea (because it makes simple things complicated). You could provide a default multiplication order, but still allow for it to be changed. To answer your question : Compute the transformation as I said above. Then, set the [/size][size=3][left]LocalTranslation to the translation vector of the transformation.[/left][/size] [left][size=3][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]Compute the quaternion as you do usually,[/font][/color][/size][/left] [left][size=3][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]I have not tested this [/font][/color][/size][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif][size=3]and some of your math function's names are a bit vague, but its something worth trying [/size][/font][/color][img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img][/left] [left][size=3][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]The idea is that you would still be rotating around (0,0,0), but then you will translate the objects to their proper locations.[/font][/color][/size][/left] [left][size=3][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]Also its very important for the SetTranslation method to set the matrix's translation vector and not multiply it by a translation matrix (in order for the above to work).[/font][/color][/size][/left] [left][size=3][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]If [/font][/color][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]you still have problems, it would be helpful if you could tell me what you are trying and what the observable result is.[/font][/color][/size][/left]

11. Math Behind Look At Matrix 4x4

There is nothing wrong in composing the LookAtMatrix directly - all you are doing is saving the matrix multiplication. However, using the LookAtMatrix, as you may have found out, is not always as practical as just composing the matrix out of rotation and translation. In your particular case, OrbitAroundTarget could be implemented as easily with either I guess. Use the following transformation to rotate around any point : // Rotate around the target point Matrix transform = Matrix().translate(target)*Matrix().rotate(angle, rotationVector)* Matrix().translate(-target); In my opinion a good generic camera class should contain just the camera transformation (and support methods for LookAt and translation/rotation) and allow you to set any matrix as the camera's transform. You can then inherit from this class and make e.g FpsCamera, OrbitAroundTargetCamera... which handle all the additional stuff. Sorry If I'm stating something you already know
12. Math Behind Look At Matrix 4x4

[quote name='Neosettler' timestamp='1329277378' post='4913224'] Thank you for your response ne0, [CODE]It has to do with the order of multiplication of the rotation and translation matrix that's used by the LookAt matrix.[/CODE] While that make sense, I’m not out of the woods yet. If it is not too much to ask, I’m wondering why you`ve mentioned one matrix for rotation and one for translation? I was under the impression the look at matrix combines rotation and translation all together and all you need is the eye, center and the up vector. [/quote] Exactly, the LookAt matrix combines rotation and translation - hence it could be decomposed into a rotation matrix and translation matrix which when multiplied together yield the LookAt matrix. Since you were wondering why the last column of the LookAt matrix takes dot products and not just eye's x, y, z - the reason is exactly because the whole LookAt matrix is composed in one step, so you don't see the actual multiplication of the rotation and translation matrices. I think what you might be forgetting is that this matrix is not applied to the camera - but the objects themsleves. So imagine you want to rotate 90 degrees to the left : [attachment=7243:Untitled.png] So imagine now you want to also move the camera's eye position by 1 unit backwards. Would it make any sense to move the object on z axis? No - you need to translate it one unit on the x axis - which is where the dot products came into place. I hope that makes any sense, because I feel I'm explaining it very poorly. Someone else (like jyk) would be able to explain it better perhaps...
13. Math Behind Look At Matrix 4x4

It has to do with the order of multiplication of the rotation and translation matrix that's used by the LookAt matrix. So if you have rotation = [ leftVector, 0 ] [ upVector, 0 ] [ fVector, 0 ] [ 0 , 0, 0, 1 ] translation = [ 0 0 0 ] [ 0 0 0 translationVector ] [ 0 0 0 ] [ 0 0 0 1 ] and your order of multiplication is rotation*translation, then the result for the last column in the lookat matrix will have the dot products. Its important to keep this order of multiplication for the lookAt matrix to have the desired effect - because you want to specify your eye position in "global coordinates" If you reverse the order - the translation will be affected by the rotation.
14. Sigh...

At least your visual styles are vastly different It could have been worse... I really hope you continue working though, your game seems to have a unique touch to it.