Top down rotating racer viewports?

Monkey Forums/Monkey Beginners/Top down rotating racer viewports?

Pixel_Outlaw(Posted 2016) [#1]
I noticed that Monkey X features viewports.

I know it can provide both canvas and sprite rotation.
Can I write a multi player game in monkey where each player gets their own viewport and the camera stays rotated the same angle as the car's direction for each one?

I could do this manually with a ton of trig math recalculating and replacing each object and using sprite rotations but I'm hoping I can keep the world intact and simply rotate the camera in a top down perspective for each player so the car always seems to point north in the viewport.

A crap car sprite my demo requires "viper.png"


Strict
Import mojo2

Class Car
	Field x:Float = DeviceWidth() / 2.0
	Field y:Float = DeviceHeight() / 2.0
	Field direction:Float = 0
	Field speed:Float = 0
	Field sprite:Image
	Field first_player:Bool 
	
	Method New(_x:Float, _y:Float, _direction:Float, _first_player:Bool = True)
		x = _x
		y = _y
		direction = _direction
		speed = 0
		Print "attempting to make new image"
		sprite = Image.Load("viper.png")
		Print "Loaded"
		first_player = _first_player
	End
	
	Method PollInputs:Void()
		Local kl:Int = KEY_LEFT
		Local kr:Int = KEY_RIGHT
		Local ku:Int = KEY_UP
		Local kd:Int = KEY_DOWN
		If Not first_player Then kl = KEY_A
		If Not first_player Then kr = KEY_D
		If Not first_player Then ku = KEY_W
		If Not first_player Then kd = KEY_S
		
		If KeyDown(kl) Then direction += 2
		If KeyDown(kr) Then direction -= 2
		If KeyDown(ku) Then speed += .1
		If KeyDown(kd) Then speed -= .5
		
		If speed > 4 Then speed = 4
		If speed < -2 Then speed = -2
	End
	
	Method Move:Void()
		PollInputs()
		x += Cos(direction) * speed
		y -= Sin(direction) * speed
	End
End

Class Test Extends App
	Field canvas:Canvas
	Field my_car:Car
	Field my_car2:Car
	Method OnCreate:Int()
		' Initialize data here
		canvas=New Canvas()
		SetUpdateRate(60)
		my_car = New Car(DeviceWidth() / 2, DeviceHeight() / 2, 0)
		my_car2 = New Car(DeviceWidth() / 2 + 128, DeviceHeight() / 2, 0, False)
		Return 0
	End
	
	Method DrawCar:Void()
		canvas.SetColor(0.0, 0.0, 1.0, 1.0)
		canvas.DrawImage(my_car.sprite, my_car.x, my_car.y, my_car.direction)
		canvas.SetColor(1.0, 0.0, 0.0, 1.0)
		canvas.DrawImage(my_car2.sprite, my_car2.x, my_car2.y, my_car2.direction)
	End
	
	Method DrawGrid:Void()
		Local x_divs:Float = 20
		Local x_step:Float = DeviceWidth() / x_divs
		Local y_divs:Float = 15
		Local y_step:Float = DeviceHeight() / y_divs
		canvas.SetColor(1, 0, 0, 1)
		For Local x:Int = 0 To x_divs - 1
			canvas.DrawLine(x * x_step, 0, x * x_step, DeviceHeight())
		Next
		canvas.SetColor(1, .5, 0, 1)
		For Local y:Int = 0 To y_divs - 1
			canvas.DrawLine(0, y * y_step, DeviceWidth(), y * y_step)
		Next
	End

	Method OnUpdate:Int()
		' Game logic here
		my_car.Move()
		Return 0
	End
	
	Method OnRender:Int()
		canvas.Clear(0, 0, 0)
		DrawGrid()
		canvas.SetColor(1, 1, 1)
		DrawCar()
		canvas.Flush()
		Return 0
	End
End

Function Main:Int()
	New Test
	Return 0
End



Gerry Quinn(Posted 2016) [#2]
You can just draw the world from each car's perspective in a separate window, using SetScissor() to define the drawn area. It will be no different from rendering a single car in its environment, except you do it twice.

I'm not familiar with the viewport functionality, but it should be able to handle this. But even if it doesn't, you just have to rotate everything in the world around the car by the same amount.


Pixel_Outlaw(Posted 2016) [#3]
I need help with rotation now. The translation is working to emulate a centered camera in the code below. (Grab the car images from the initial post if you need them to run the code below)

Well some time later I've managed to get a camera that follows a car around.
What I need is the camera to stay focused on the car's position (as I've done below) but also rotate so the car always points north in the view.
THAT is the part I need help with. I don't want to manually rotate the entire world around the car using trig. That is best left to the matrix operations of the canvas.

Strict
Import mojo2

Class Car
	Field x:Float = DeviceWidth() / 2.0
	Field y:Float = DeviceHeight() / 2.0
	Field direction:Float = 0
	Field speed:Float = 0
	Field sprite:Image
	Field first_player:Bool 
	
	Method New(_x:Float, _y:Float, _direction:Float, _first_player:Bool = True)
		x = _x
		y = _y
		direction = _direction
		speed = 0
		Print "attempting to make new image"
		sprite = Image.Load("viper.png")
		Print "Loaded"
		first_player = _first_player
	End
	
	Method PollInputs:Void()
		Local kl:Int = KEY_LEFT
		Local kr:Int = KEY_RIGHT
		Local ku:Int = KEY_UP
		Local kd:Int = KEY_DOWN

		If KeyDown(kl) Then direction += 2
		If KeyDown(kr) Then direction -= 2
		If KeyDown(ku) Then speed += .1
		If KeyDown(kd) Then speed -= .5
		
		If speed > 4 Then speed = 4
		If speed < -2 Then speed = -2
	End
	
	Method Move:Void()
		PollInputs()
		x += Cos(direction) * speed
		y -= Sin(direction) * speed
	End
End

Class Test Extends App
	Field canvas:Canvas
	Field my_car:Car
	Field my_car2:Car
	Method OnCreate:Int()
		' Initialize data here
		canvas=New Canvas()
		SetUpdateRate(60)
		' Two Car objects, we'll only be able to move car 1
		my_car = New Car(DeviceWidth() / 2, DeviceHeight() / 2, 0)
		my_car2 = New Car(DeviceWidth() / 2 + 128, DeviceHeight() / 2, 0, False)
		Return 0
	End
	
	Method DrawCar:Void()
		' Draw both cars
		canvas.SetColor(0.0, 0.0, 1.0, 1.0)
		canvas.DrawImage(my_car.sprite, my_car.x, my_car.y, my_car.direction)
		canvas.SetColor(1.0, 0.0, 0.0, 1.0)
		canvas.DrawImage(my_car2.sprite, my_car2.x, my_car2.y, my_car2.direction)
	End
	
	Method DrawGrid:Void()
		' Draw simple grid to help see car movment
		Local x_divs:Float = 20
		Local x_step:Float = DeviceWidth() / x_divs
		Local y_divs:Float = 15
		Local y_step:Float = DeviceHeight() / y_divs
		canvas.SetColor(1, 0, 0, 1)
		For Local x:Int = 0 To x_divs - 1
			canvas.DrawLine(x * x_step, 0, x * x_step, DeviceHeight())
		Next
		canvas.SetColor(1, .5, 0, 1)
		For Local y:Int = 0 To y_divs - 1
			canvas.DrawLine(0, y * y_step, DeviceWidth(), y * y_step)
		Next
	End

	Method OnUpdate:Int()
		my_car.Move()
		Return 0
	End

	Method OnRender:Int()
	    
	    'Vars to position "camera" offsets
		Local half_width:Float = DeviceWidth() * .5
		Local half_height:Float = DeviceHeight() * .5
		Local pos_x:Float = (my_car.x - half_width) * -1
		Local pos_y:Float = (my_car.y - half_height) * -1
		
		'Move camera to car's center
		canvas.Clear(0, 0, 0)
		canvas.PushMatrix()
		canvas.Translate(pos_x, pos_y)
		DrawGrid()
		canvas.SetColor(1, 1, 1)
		DrawCar()
		canvas.PopMatrix()
		
		canvas.Flush()
		
		Return 0
	End
End

Function Main:Int()
	New Test
	Return 0
End



Gerry Quinn(Posted 2016) [#4]
Rotate the world using matrix operations. Then draw the world but *not* the car. Then draw the car un-rotated (or rotated to face north or whatever, maybe you wiggle it slightly in the appropriate direction when it's turning.)


Ashmoor(Posted 2016) [#5]
From what i've seen ignitionX or Pyro sounds like the perfect solution to your problems :) maybe give it a try.


Pixel_Outlaw(Posted 2016) [#6]
Rotate the world using matrix operations. Then draw the world but *not* the car. Then draw the car un-rotated (or rotated to face north or whatever, maybe you wiggle it slightly in the appropriate direction when it's turning.)

In order to draw the world correctly the center of the view needs to be positioned where the car is and rotated the cars direction + 90 degrees.


From what i've seen ignitionX or Pyro sounds like the perfect solution to your problems :) maybe give it a try.

Thanks for the advice but the solution to this problem just requires 3 - 5 or so lines of code to move to the car's position then rotate the world appropriately.
It's a math problem that I'm working on more than needing additional functionality and bolting a framework on.

I guess I'll just keep trying to get the math correct here.


Gerry Quinn(Posted 2016) [#7]
Sounds like you have it, just fiddle with the translations/rotations until it works.