help with zoom

BlitzMax Forums/BlitzMax Programming/help with zoom

Cruis.In(Posted 2006) [#1]
hey everyone, ive been experimenting with adding zoom with the mouse wheel. per my code entry in the code base under zooming.

the only problem with that, is I am using set scale... and adjusting the scale based on the input of the mouse wheel. set scale (1.0 + newscale) etc... you get the idea. so it zoom into and out, i applied it to each element drawn, ships, planets, however, its not proportionately correct.

instead of remaining the same distance apart from one another, the ships appear to get closer, or further away from one another, instead of just becoming bigger or smaller, and the relevant distance is not maintained.

any commands in the 2d set can help? Ive experimented with glscale and stuff under opengl, basically no gains....

i need something which zooms the entire viewing area, inthis case the 1024, 768 section which is the current viewport. not just to scale images.....

am I on the right path?


REDi(Posted 2006) [#2]
Yeah, you'll just need to scale all positions as well...
SetScale(1.0 + newscale,1.0 + newscale)
DrawImage blahImage,Int(blahX*(1.0+newscale)),Int(blahY*(1.0+newscale))

If ya get ma drift :)

BTW, I wouldn't bother with the 1+newscale bit, just have newscale as the actual scale factor.


Cruis.In(Posted 2006) [#3]
scale all positions? is this different than scaling all other ships and planets? because as i started in my post, i applied it too all images on screen, the planets and ships. And it does the thing i say its doing, it aint correct.

so all positions is?


REDi(Posted 2006) [#4]
by position I mean the x,y coords used by DrawImage, like in the example.


Cruis.In(Posted 2006) [#5]
how do you scale x y coords?

dont you just scale the image itself? setscale (1.0, 1.0)

1.0 being normal size, 2.0 twice the size, and less than 1.0 being starting to shrink the image, hence setting the scale of the image, and not the x and y of where it is...


REDi(Posted 2006) [#6]
Heres two examples to show what I mean, one with no position scaling...

And one with...


how do you scale x y coords?

I gave you an example of how to do it in my first post.


Cruis.In(Posted 2006) [#7]
I have the feeling I am doing the code right, but applying the "newscale" wrong. your code looks like mine yet the distance is not maintained, at least you understand what I am saying, because your example shows the three corners of the cube together, and still the same distance when zoomed in.

i think i understood wehat you meant by scale the coords, I added my newscale variable, to the coords,
drawimage (image, x+newscale, y+newscale)

but it didn't solve the problem i described to you, yet your code works...

could midhandle be causing a problem?


Cruis.In(Posted 2006) [#8]
aha, i tried them again, your first one like you said, is incorrect and does exactly what my images are doing, going closer are further apart, even though they have not in fact moved, but only been zoomed.

yet i still cannot get mine right, could setorigin by doing anything to it?


REDi(Posted 2006) [#9]

drawimage (image, x+newscale, y+newscale)


should be
drawimage (image, x*newscale, y*newscale)

multiply position by scale


Cruis.In(Posted 2006) [#10]
why does multiply make it right though? once you are changing the scale isnt that enough?


Cruis.In(Posted 2006) [#11]
still doesnt work for me, i put 3 enemy ships as bots on the screen, drawimage (shipimage, x*newcale, y*newscale)

my own ship which is in the centre is also drawn according to new scale, they dift close together and apart and never remain constant. something else must be wrong somewhere with the function zoom i am using, but i dont see how...


**************************

Function ZoomCamera()
Local MaxZoom:Float = 3.0
Local minzoom:Float = -0.8
Local speed:Float = 0.03
Local set_Zoom:Float
Local zoom

'mouse wheel value = to variable zoom
zoom = MouseZ()

set_Zoom = 0.2 * zoom

'stop ship from becoming unviewable if player is at warp and is zooming out int..
If ship.isWarp= True Then minzoom = -0.2

'limit max zoom in
If set_Zoom > maxZoom
Set_Zoom = maxZoom
End If

'zooms to the set zoom value(determined by how much you scroll)
If KeyDown(KEY_Z) = 0 And set_Zoom > newScale
newscale :+ speed
End If

'same as above
If KeyDown(KEY_X) = 0 And set_Zoom < newScale
newscale :- speed
End If

'limit zoom out
If newscale < minZoom
newscale = minZoom
End If

'DrawText("Newscale: "+newscale,ship.x+300,ship.y+300)
End Function

i have it done like that, so the zoom, doesnt zoom with every scroll of the wheel, but rather, so scroll alot of it, and the zoom catches up, or a delayed reaction.

do you understand the code, is something wrong with my function?


REDi(Posted 2006) [#12]
Changing the scale only changes the size of what your drawing, it doesn't effect the position its drawn on screen, thats what the x,y parameters are for ;)

*EDIT*
The code you posted looks okay to me, must be something else.

Anyway, gotta crash now, good luck :)


Cruis.In(Posted 2006) [#13]
gotta be setorigin bumming me

is the way to create an infinite world

SetOrigin(GraphicsWidth()/2-x, GraphicsHeight()/2-y)


where x, and y, in this case, are the variables holding the position of my ship in the world, and therefore as i move they change...

this way ive created "endless" space to fly in, and set the world_width and world_height, to be 2000 times the screen width and screen height. which is 1024, 768... is that just an illusion of an actual world and the reason my zooming doesnt work? or is that how its done?


Cruis.In(Posted 2006) [#14]
after more experimenting, i realise that my problem is, i have my ship in the centre, and the virtual camera is centred on the ship. the player controlled ship never leaves the centre of the screen.

i modified my code accordingly and did what you did. but while doing what you said works, the other problem is created by the fact that, the images do in fact change x and y position on the screen when you do it that way, and there fore switch to the opposite of the side they started on, hence if they began on the left of my playership, when i zoom in they switch on over to the right.

I modified your code to show you what i mean

Strict
Graphics 1024,768,0,60
Local scale# = 1.0

While Not KeyHit(KEY_ESCAPE)
Cls

SetScale(scale,scale)

SetColor(255,0,0)
DrawRect(Int(0.0*scale),Int(0.0*scale),100,100)

SetColor(0,255,0)
DrawRect(Int(100.0*scale),Int(100.0*scale),100,100)

SetColor(0,0,255)
DrawRect(Int(200.0*scale),Int(200.0*scale),100,100)

DrawRect(512,384,100,100)

SetColor(255,255,255)
DrawText("SCALED POSITION",Int(90.0*scale),Int(145.0*scale))

' USE UP AND DOWN TO CHANGE SCALE
If KeyDown(KEY_UP) Then scale:+(scale/25.0)
If KeyDown(KEY_Down) Then scale:-(scale/25.0)

Flip 1

Wend

watch, as the three rects, on the top left, move downward and to the right and cross over the rect in the middle, in this case the rect represents my ship.

the rects resize correctly, but dont stay where they were in relation to the ship, before the zoom, this is what i need to figure out. what we coded is fine, it doesn what we're saying, the thing is, can it be changed to do what i want, which is what i described above.


AlexO(Posted 2006) [#15]

If KeyDown(KEY_UP) Then scale:+(scale/25.0)
If KeyDown(KEY_Down) Then scale:-(scale/25.0)



this approaches zero but never hits zero if I read that correctly. Just wanted to note that.

From reading you're code you want the zoom functionality to focus in and out of your ship.

that would never work with the code you posted above. You're ship will *always* be drawn at 512,384. When you scale up all of your other rectangles will move according to the origin (which I assume is in the top left). What you need to do is to scale everything relative to the ship, not the 0,0 origin.

I'll try to explain it here and show an example

1) You need to find the distance from your ship to the real origin (0,0). Which in this case would be easy: you're ship's x,y. Let us call this vector S.

2) You can express all the other rectangles' positions in relation to your ship's position. So for instance, if my ship is at 300,300 and a rectangle at 100,100. The rectangle's relative position to my ship is -200,-200. Let's call this rectangle's absolute position (100,100) vector R.

3) To zoom in and out with the ship being the central focus I have to transform all of the objects' positions I want to zoom to the ship's coordinate space. This is achieved by taking the vector (R - S) and then scaling THAT result, call it A. Now take A and add S back to it.

Some example code
(note: this hasn't been tested because I am not on a computer with blitzmax installed)

Strict
Graphics 1024,768,0,60
Local scale# = 1.0
' rectangle positions
local rx1# = 100
local ry1# = 100
local rx2# = 300
local ry2# = 300
local rx3# = 600
local ry3# = 600

local shipx# = 512
local shipy# = 384

While Not KeyHit(KEY_ESCAPE)
Cls

SetScale(scale,scale)

SetColor(255,0,0)
' explanation from above:
' (R - S) * scale + S
local drawx# = ((rx1 - shipx) * scale) + shipx
local drawy# = ((ry1 - shipy) * scale) + shipy
DrawRect(drawx,drawy,100,100)

SetColor(0,255,0)
drawx# = ((rx2 - shipx) * scale) + shipx
drawy# = ((ry2 - shipy) * scale) + shipy
DrawRect(drawx,drawy,100,100)

SetColor(0,0,255)
drawx = ((rx3 - shipx) * scale) + shipx
drawy = ((ry3 - shipy) * scale) + shipy
DrawRect(drawx,drawy,100,100)

DrawRect(shipx,shipy,100,100)

SetColor(255,255,255)
DrawText("SCALE: " + scale, 50, 50)

' USE UP AND DOWN TO CHANGE SCALE
If KeyDown(KEY_UP) Then scale:+(scale/25.0)
If KeyDown(KEY_Down) Then scale:-(scale/25.0)

Flip 1

Wend



please excuse the lengthy explanation, but I'd rather explain it to someone and have them learn it rather than copy/paste code :).


tonyg(Posted 2006) [#16]
Do the examples here help?


Cruis.In(Posted 2006) [#17]
thanks for the help guys, Alex O, just to be clear, before i go through your code step by step. I am setting the origin with SetOrigin(GraphicsWidth()/2-x, GraphicsHeight()/2-y)

where x and y in that case, is my ship's X and Y position. I am not setting the origin as 0,0
that being said, i believe you are right when you say i am scaling everything relative to 0,0 and not my ship.


AlexO(Posted 2006) [#18]
Hmmm,
I haven't messed with SetOrigin() commands for a while, but the process I described above shouldn't change. The only thing that would be affected would be #1 where you find the distance vector from you're ship to the real origin. So if it you use SetOrigin(GW()/2 - x, GH()/2 -y) Then the general case for finding this vector I think would be:
S = (newOriginPosition - OldOrigin)
where newOriginPosition would be your ship's x/y, and oldOrigin being that equation you use for setOrigin().

I hope I got that right :). It's much too early in the morning for this kind of stuff >_<.


Cruis.In(Posted 2006) [#19]
Alex I understood and applied your code, it works good.

One little problem is this

Local drawx# = ((rx1 - shipx) * scale) + shipx
Local drawy# = ((ry1 - shipy) * scale) + shipy

using that formula I applied the following code to two test ships, which i use as targetting bots

Local scimxx = ((scimx - ship.x) * newscale) + ship.x
Local scimyy = ((scimy - ship.y) * newscale) + ship.y

i know the variables are confusing, but its just a test plus you know that drawx has become scimx for me.

now the problem is, when I move my own ship, those ships jitter slightly noticeable because as you can see there X and Y position change based on my ship.x
In your example, you had shipx and shipy fixed at 512, 384. My ship is drawn to ship.x and ship.y which change from 512, 384, as I move because the origin is set to graphicswidth()/2, graphicsheight()/2 which is 512/384

but with the origin sticking there, when I move, you know my ship.x becomes 512 + where I go on the xplane, and 384 + where i go on the y plane.

now while its true they dont appear to move from position because after subtracting ship.x initially, you then add it back at the end of the forumla, it means its constantly subtracting adding, and keeping the other ships in place as I move, but gives the jitter effect.

did i explain well enough?
anyway I can modify your formula to solve that quirk?


AlexO(Posted 2006) [#20]
A jitter effect is usually the cause of a float to int casting issue when you calculate the draw coordinates and/or calculate the setOrigin() coordinates.


Local scimxx = ((scimx - ship.x) * newscale) + ship.x
Local scimyy = ((scimy - ship.y) * newscale) + ship.y



If the above is in fact the exact code you are using then I think scimxx is an int and not a float. Not sure about ship.x/y. But due to slight innaccuracies when casting from float to int you'll probably get that effect.

I would try making those coordinates all floats explicity (Blitzmax can draw at decimal values last I checked), and see if that solves it. I wouldn't worry about the 'slowness' of floats compared to ints if all you are making is a side-scrolling shooter or something similar.

Now, I think SetOrigin() only takes integers as parameters. If ship.x is a float then I would try casting to int the parameters you pass to setorigin().

SetOrigin(int(GraphicsWidth()/2-ship.x),int(graphicsheight()/2-ship.y))

Those are the only two things I can think of at the moment. I have had this issue before with a 2D camera class I made. When I get home tonight I could look into how I fixed it if you are still having issues.


Cruis.In(Posted 2006) [#21]
Strict

Global ViewX:Float, ViewY:Float
Global ViewZoom:Float = 1.0

Global EntityList:TList = CreateList()
Type TEntity
	Field X:Float
	Field Y:Float
	
	Function Create:TEntity (_X:Float, _Y:Float)
		Local Entity:TEntity = New TEntity
		Entity.X = _X
		Entity.Y = _Y
		EntityList.AddLast(Entity)
		Return Entity
	End Function

	Method Render()
		Local ScreenX:Float = (X * ViewZoom) + ViewX
		Local ScreenY:Float = (Y * ViewZoom) + ViewY
				
		DrawRect ScreenX-(3*ViewZoom), ScreenY-(3*ViewZoom),(6*ViewZoom),(6*ViewZoom)
	End Method
End Type

Graphics 640,480

For Local I:Int = 1 To 50
	TEntity.Create(Rnd(-256,GraphicsWidth()+256),Rnd(-256,GraphicsHeight()+256))
Next

Local Player:TEntity = TEntity.Create(640,480)

While Not KeyHit(KEY_ESCAPE)
	Cls
	SetOrigin (GraphicsWidth() / 2),(GraphicsHeight() / 2)


	ViewZoom :+ (KeyDown(KEY_NUMADD)-KeyDown(KEY_NUMSUBTRACT)) * 0.1
	
	Player.X :+ (KeyDown(KEY_RIGHT)-KeyDown(KEY_LEFT))
	Player.Y :+ (KeyDown(KEY_DOWN)-KeyDown(KEY_UP))
	
	ViewX = -Player.X * ViewZoom
	ViewY = -Player.Y * ViewZoom
	
	For Local Entity:TEntity = EachIn EntityList
		SetColor 255,0,0
		If Entity = Player SetColor 0,255,0
		Entity.Render()
	Next
	
	Flip
	
Wend


thats a pice tonyg posted

i can see here he applies the zoom to the size of the rect.

DrawRect ScreenX-(3*ViewZoom), ScreenY-(3*ViewZoom),(6*ViewZoom),(6*ViewZoom)

but in your example Alex, you didn't do that. Yet, when you "zoom" in with your example, the rects get bigger and smaller, and the only variable you modified was there X and Y positions. modifying where they are, should make them only move about the screen, not appear to become bigger or smaller.

weird. can't figure that part out.

For me with my images, I apply the *newscale, to the setscale of my drawn target ships. because merely applying to the X and Y draw coords moves them ABOUT the screen like what I am saying your code "SHOULD" do and doesn't make them bigger or smaller. So basically now as I use the mouse wheel and zoom out, the ship becomes "smaller" by changing the scale, and the x and y coords are modified moving it closer to my ship. so that the change in size is offset by the movement closer to my ship, so that it is still the same distance away from my ship before I changed the level of zoom.

or vice versa, so that the movement closer to my ship is offset by the drop in size.

will this work for multiplayer? its supposed to be amultiplayer game. when I "zoom" now I am merely changing the "drawing" coords and not where the enemy ship has actually moved to, so what I mean to say is, if I am zooming, I won't be invariably moving his ship closer to my in actual fact will I? only the graphical part...


AlexO(Posted 2006) [#22]
tonyg's example applies the zoom to the rect because he does not use setScale() before he draws.

Now, if you used an image to draw your entities instead of simple rectangles tonyg's example would not work without modification.

..
SetScale(scale,scale)
...

is what makes the one I wrote up there work with any image/rect/oval. Check blitzmax documentation for more info on that command.

As long as those entities keep a hold of their own original world coordinates then multiplayer will work. You would send their 'world' coordinates (rx1/y1 in my example) and not their 'drawing' coordinates (the drawx/y in my example). It's a good idea to keep game world coordinates separate from graphical coordinates.


Cruis.In(Posted 2006) [#23]
i forget, yeah i saw that, sorry... :)


AlexO(Posted 2006) [#24]
no problem


Cruis.In(Posted 2006) [#25]
thanks so much. means alot

my last question there about multiplayer?

because with this
x = ((xx - ship.x) * newscale) + ship.x
		y = ((yy - ship.y) * newscale) + ship.y


i have to apply that to all the x and y coords of whatever I draw. not soo bad.
However what that does, is change the x and y coords of these ships, planets, etc, when I zoom, and when I am moving the player ship, these objects x and y coords change accordingly.

This is not seen on screen, because they are being drawn in relation to the player ship, while i can still fly "past" them and they are not attached to me like a glue, i am wondering, if this poses a problem, for multiplayer... and if the positioning is still true? and is it that the coords dont matter once I apply the offset, and things move relatively how they should. ?


AlexO(Posted 2006) [#26]
The positioning will still hold true to what everybody sees as long as everyone that is playing is using the same world coordinate system (which by default they will be so no extra setup or coding needed).

that x and y are nothing but graphical coordinates. The world (or you can call them 'real') coordinates for each object you are drawing is xx and yy. XX and YY would be the positional information you would need to send over the wire, and the client could calculate its own graphical coordinates with that info.


Cruis.In(Posted 2006) [#27]
i have another problem,

when I zoom with the mouse wheel, i keeps applying the 0.3 to the coords after i have stopped zooming.

because of my zooming variables, like how fast i have it set to zoom based on the mouse wheel which is 0.2 * mousez(), so its mouse and not jerky...

so now i increase the zoom by a speed factor of 0.3 while i scroll. so when i stop, the x and y pos of my ship is still being changed by that number, rapidly, and also the enemy ships positions of course, because they are being drawn relative to mine of course.

so its making heck with the collision detection. because the ship graphic is just basically a lifeless bot, it does is not moving when the virtual coords change. However, we know that it is moving, its just that because of the code my ship is moving relative to it, so it appears to be standing still. so the collision detection is all awry.

here is the collision that works no matter what. because the ship at 700,700, is fixed at 700.700 i drew it to that. without any formulas.

If ImagesCollide(torpedo.photonimage, torpedo.x, torpedo.y,torpedo.frame,voyager,700,700,0)


that works perfect, no matter how much i zoom or where i move.

If ImagesCollide(torpedo.photonimage, torpedo.x, torpedo.y,torpedo.frame,enemyship1.shipimage,enemyship.x,enemyship.y,0)


thats where the collision goes awry when i move and stuff.


of course i have not applied this formula to the torpedo object yet, because i cant get it right with it just yet.
because the torpedo is a constant moving object different than the lifeless ships. just applying the
x = ((xx - ship.x) * newscale) + ship.x


to the torpedo code ...
doesn't cut it for it apparantly :)

and because the torpedo has

torpedo.x = ship.x + (Sin(torpedo.angle) * torpedo.torpedoSpeed) * delta'so torp orgin from ship
		torpedo.y = ship.y - (Cos(torpedo.angle) * torpedo.torpedoSpeed) * delta


to work out first, so that it can fire in the correct direction etc... bearing in mind i have another set of code firing the torpedo object, towards where my mouse pointer is on screen. but thats un important.

the torpedo x and y needs that above code too.

edit

now i am not sure what is causing the continuous movement after i stop. i accelerate, then press space bar for an emergency stop, and the .000 are still moving, not the whole numbers.


AlexO(Posted 2006) [#28]
I have the feeling you're implementing the equation i posted a bit wrong. Even if that torpedo has a complex coordinate path it still shouldn't matter.

The code to draw that torpedo on the screen correctly should be
...
torpedo.x = ship.x + (Sin(torpedo.angle) * torpedo.torpedoSpeed) * delta'so torp orgin from ship
		torpedo.y = ship.y - (Cos(torpedo.angle) * torpedo.torpedoSpeed) * delta

x = ((torpedo.x - ship.x) * newscale) + ship.x
'... same for y.

DrawImage(torpedo.image, x, y)


again, your entity.x/y are your world coordinates and do not relate to anything (well almost...i'll get to that in a bit) with drawing. that single variable 'x' must be calculated before each draw command based on two parameters: the ship's x and the torpedo.x.

Now, with the collision...I've never used ImageCollide() but from the looks of it; it looks like it takes into account the screen (drawing) coordinates and scale/rotation to produce the correct response. So you have to give the function your drawing cooridnates and not your world coordinates.

i.e.:
tx# = ((torpedo.x - ship.x) * newscale) + ship.x
ty# = ((torpedo.y - ship.y) * newscale) + ship.y

ex# = ((enemyship.x - ship.x) * newscale) + ship.x
ey# = ((enemyship.y - ship.y) * newscale) + ship.y

If ImagesCollide(torpedo.photonimage,tx, ty,torpedo.frame,enemyship1.shipimage, ex, ey,0)


Since I don't know completely what you are trying to do all I can offer is bits of examples in hopes that it is in the right direction. With that said, funny that you posted when you did as I'm in the middle of writing a series of tutorials on this very subject (2D camera movements/zooming/rotation) so that's why its somewhat fresh in my mind. You can keep an eye on the blitzmax tutorials forum as I'll be posting them there in the coming weeks.


Cruis.In(Posted 2006) [#29]
i can show you all the source code if you like.

and tell you where we are. and you woud understand it better.

the problem I am having with giving the torpedo that code is where it goes. before the formula was one formula, now theres the previous formula to take into account, do i add the forumula to that one line for torpedo.x or.... do i put it before etc... tried both, might not have done it right, but i dont know which one would be right, since neither worked the way i did it.


AlexO(Posted 2006) [#30]
you can e-mail me alex@... if you wish and we can discuss the rest over e-mail and you can send source if you want me to look at it.