Array index out of range + identifier not found.

8 replies to this topic
Posted 2 months ago #1
Crispy

Need some help, I'm fairly new to monkey x and I cant understand why this code wont run. It started by giving me the array index out of range for my projectile array when a new projectile was fired (line 211). Then while attempting to fix it, it has begun saying that the Player identifier cannot be found on line 253 and has stopped compiling at all. If I've missed any sections out or if you have any tips, please enlighten me. I apologise for the general poor presentation and such :/

Import mojo
Import extended

Function Main()
	New StarshipBastion()
	
End

Const STATE_MENU:Int = 0
Const STATE_OPTIONS:Int = 1
Const STATE_CONTROLS:Int = 2
Const STATE_GAME:Int = 3
Const STATE_DEATH:Int = 4
Global projectileArray : List<Projectile>

Class StarshipBastion Extends App
	
	Field gameState:Int = STATE_MENU
	Field Test1:Image
	Field Test2:Image
	Field Test3:Image
	Field background:Image
	Field title:Image
	Field menu:Image
	Field random:Bool = False
	Field spaceship:Image
	Field pirate:Image
	Field Player:Spaceship
	
	
	Method OnCreate()
	
		SetUpdateRate(60)
		Test1 = LoadImage ("TestImage.png")
		Test2 = LoadImage ("TestImage2.png")
		Test3 = LoadImage ("TestImage3.png")
		background = LoadImage ("background.png")
		title = LoadImage ("title.png")
		menu = LoadImage ("menu2.png")
		pirate = LoadImage ("pirate.png")
		Player = New Spaceship
		
	End
	
	Method OnUpdate()
		Select gameState
			Case STATE_MENU
				If KeyHit(KEY_ENTER)
					gameState = STATE_GAME
				End
			Case STATE_OPTIONS
			
			Case STATE_CONTROLS
			
			Case STATE_GAME
			
				If KeyHit(KEY_ENTER)Then random = True
				If KeyHit(KEY_R) Then Player.Reset()
				
				For Local projectile:= Eachin projectileArray
				
					projectile.Update()
					
				Next
				
				Player.Update()
			
			Case STATE_DEATH
			
		End
	End
	
	Method OnRender()
		Cls(0, 0, 0)
		
		Select gameState
			Case STATE_MENU
			
				DrawImage(menu, 0, 0)
				DrawText("Press Enter to Play", 320, 400, 0.5)
				
			Case STATE_OPTIONS
			
			Case STATE_CONTROLS
			
			Case STATE_GAME
			
				#GLFW_WINDOW_WIDTH=1000
				#GLFW_WINDOW_HEIGHT=600
				
				Cls(255, 255, 255)
				DrawImage(background, 0, 0, 0, 1, 1, 0)
				 
				For Local projectile:= Eachin projectileArray
					
					projectile.Draw()
					
				Next
				
				Player.Draw()
			
			Case STATE_DEATH
		End
	End
End

Class Vector                                                                    'TO REMOVE?'
	
	Field x:Float
	Field y:Float
	
	Method New(x:Float = 0, y:Float = 0)
		Set(x, y)
	End
	
	Method Set(x:Float, y:Float)
		Self.x = x
		Self.y = y
	End
End

Class Spaceship

	Field spaceshipSprite:Image = LoadImage ("Spaceship.png", 1, Image.MidHandle)
	
	Field rotation:Float
	
	Field turnSpeed:Float = 0
	
	Const turnAcceleration:Float = 1.4
	Const turnDeceleration:Float = 0.4
	
	Field positionX:Float = 100
	Field positionY:Float = 50
	
	Field origPositionX:Float = 100
	Field origPositionY:Float = 100
	
	Field speedX:Float = 0
	Field speedY:Float = 0
	Field trueSpeed:Float = 0
	
	Const acceleration:Float = 0.2
	Const deceleration:Float = 0.05
	
	Method Update() 
	
		If KeyDown(KEY_D) 
			turnSpeed += turnAcceleration
		End
		
		If KeyDown(KEY_A)
			turnSpeed -= turnAcceleration
		End
		
		If turnSpeed > 5 Then turnSpeed = 5
		If turnSpeed < -5 Then turnSpeed = -5
		
		rotation += turnSpeed
		
		If rotation > 360 Then rotation -= 360
		If rotation < 0 Then rotation += 360
		
		If turnSpeed > turnDeceleration
			turnSpeed -= turnDeceleration
		End
		
		If turnSpeed < -turnDeceleration 
			turnSpeed += turnDeceleration
		End
			
		If turnSpeed < turnDeceleration And turnSpeed > -turnDeceleration 
			turnSpeed = 0
		End
		
		If KeyDown(KEY_W) 
			speedX += acceleration * Sin(rotation)
			speedY -= acceleration * Cos(rotation)
		End
		
		If KeyDown(KEY_S)
			speedX -= acceleration * Sin(rotation)
			speedY += acceleration * Cos(rotation)
		End
		
		trueSpeed = Sqrt((speedX * speedX) + (speedY * speedY))
		
		If trueSpeed > 0
			speedX -= (speedX / trueSpeed) * deceleration
			speedY -= (speedY / trueSpeed) * deceleration
		End
		
		If trueSpeed > 5
			speedX += (speedX / trueSpeed) * (5 - trueSpeed)
			speedY += (speedY / trueSpeed) * (5 - trueSpeed)
		Endif
		
		positionX += speedX
		positionY += speedY
		
		If positionX < 0 Then positionX = 0 
		If positionX > 1000 Then positionX = 1000
		
		If positionY < 50 Then positionY = 50
		If positionY > 600 Then positionY = 600
		
		If KeyHit(KEY_SPACE)
		
			projectileArray[projectileArray.Length + 1] = New Projectile
			
		End

	End
	
	Method Reset()
	
		positionX = origPositionX
		positionY = origPositionY
		speedX = 0
		speedY = 0
		rotation = 0
	
	End
	
	Method Draw()
	
		DrawImage(spaceshipSprite, positionX, positionY, -rotation, 1, 1, 0)
		
	End

End

Class Projectile
	
	Field projectileSprite:Image = LoadImage("projectiles.png", 1, Image.MidHandle)
	
	Field positionX:Float
	Field positionY:Float
	
	Field speedX:Float
	Field speedY:Float
	
	Field rotation:Float
	
	Field trueSpeed:Float = 8
	
	Method New()
	
		speedX = (trueSpeed * Cos(rotation))
		speedY = (trueSpeed * Sin(rotation))
		positionX = Player.positionX
		positionY = Player.positionY
		rotation = Player.rotation
	
	End 
	
	Method Draw()
		
		DrawImage(projectileSprite, positionX, positionY, -rotation, 1, 1, 0)
		
	End
	
	Method Update()
	
		positionX += speedX
		positionY += speedY
		
		If positionX > 1000 Or positionX < 0 Or positionY > 600 Or positionY < 50
		
			projectileArray.Remove(Self) 
			
		End
	
	End
		

End
 
Posted 2 months ago #2
Gerry Quinn

Player is a field of the single StarshipBastion instance. Projectile needs to be able to find it. I made a global theSB:StarshipBastion which allows it to do so. Projectile can now access theSB.Player.

I also renamed projectileArray to projectiles ('cos it's not an array...). It has to be initialised (done in OnCreate() ). Also, Lists don't have a Length() property. You can call Count() to count the elements, but anyway what you wanted was AddLast() instead.

(Array index out of range happened because arrays have a fixed size. Trying to access the element at length+1 causes this error. Lists can grow freely, and a Stack would also work.)

It runs now but the screen is blank as you aren't creating any projectiles.

Import mojo
Import extended

Function Main()
	theSB = New StarshipBastion()
End

Const STATE_MENU:Int = 0
Const STATE_OPTIONS:Int = 1
Const STATE_CONTROLS:Int = 2
Const STATE_GAME:Int = 3
Const STATE_DEATH:Int = 4
Global projectiles : List<Projectile>
Global theSB:StarshipBastion


Class StarshipBastion Extends App
	
	Field gameState:Int = STATE_MENU
	Field Test1:Image
	Field Test2:Image
	Field Test3:Image
	Field background:Image
	Field title:Image
	Field menu:Image
	Field random:Bool = False
	Field spaceship:Image
	Field pirate:Image
	Field Player:Spaceship
	
	
	Method OnCreate()
	
		SetUpdateRate(60)
		Test1 = LoadImage ("TestImage.png")
		Test2 = LoadImage ("TestImage2.png")
		Test3 = LoadImage ("TestImage3.png")
		background = LoadImage ("background.png")
		title = LoadImage ("title.png")
		menu = LoadImage ("menu2.png")
		pirate = LoadImage ("pirate.png")
		Player = New Spaceship
		projectiles = New List< Projectile >()
	End
	
	Method OnUpdate()
		Select gameState
			Case STATE_MENU
				If KeyHit(KEY_ENTER)
					gameState = STATE_GAME
				End
			Case STATE_OPTIONS
			
			Case STATE_CONTROLS
			
			Case STATE_GAME
			
				If KeyHit(KEY_ENTER)Then random = True
				If KeyHit(KEY_R) Then Player.Reset()
				
				For Local projectile:= Eachin projectiles
				
					projectile.Update()
					
				Next
				
				Player.Update()
			
			Case STATE_DEATH
			
		End
	End
	
	Method OnRender()
		Cls(0, 0, 0)
		
		Select gameState
			Case STATE_MENU
			
				DrawImage(menu, 0, 0)
				DrawText("Press Enter to Play", 320, 400, 0.5)
				
			Case STATE_OPTIONS
			
			Case STATE_CONTROLS
			
			Case STATE_GAME
			
				#GLFW_WINDOW_WIDTH=1000
				#GLFW_WINDOW_HEIGHT=600
				
				Cls(255, 255, 255)
				DrawImage(background, 0, 0, 0, 1, 1, 0)
				 
				For Local projectile:= Eachin projectiles
					
					projectile.Draw()
					
				Next
				
				Player.Draw()
			
			Case STATE_DEATH
		End
	End
End

Class Vector                                                                    'TO REMOVE?'
	
	Field x:Float
	Field y:Float
	
	Method New(x:Float = 0, y:Float = 0)
		Set(x, y)
	End
	
	Method Set(x:Float, y:Float)
		Self.x = x
		Self.y = y
	End
End

Class Spaceship

	Field spaceshipSprite:Image = LoadImage ("Spaceship.png", 1, Image.MidHandle)
	
	Field rotation:Float
	
	Field turnSpeed:Float = 0
	
	Const turnAcceleration:Float = 1.4
	Const turnDeceleration:Float = 0.4
	
	Field positionX:Float = 100
	Field positionY:Float = 50
	
	Field origPositionX:Float = 100
	Field origPositionY:Float = 100
	
	Field speedX:Float = 0
	Field speedY:Float = 0
	Field trueSpeed:Float = 0
	
	Const acceleration:Float = 0.2
	Const deceleration:Float = 0.05
	
	Method Update() 
	
		If KeyDown(KEY_D) 
			turnSpeed += turnAcceleration
		End
		
		If KeyDown(KEY_A)
			turnSpeed -= turnAcceleration
		End
		
		If turnSpeed > 5 Then turnSpeed = 5
		If turnSpeed < -5 Then turnSpeed = -5
		
		rotation += turnSpeed
		
		If rotation > 360 Then rotation -= 360
		If rotation < 0 Then rotation += 360
		
		If turnSpeed > turnDeceleration
			turnSpeed -= turnDeceleration
		End
		
		If turnSpeed < -turnDeceleration 
			turnSpeed += turnDeceleration
		End
			
		If turnSpeed < turnDeceleration And turnSpeed > -turnDeceleration 
			turnSpeed = 0
		End
		
		If KeyDown(KEY_W) 
			speedX += acceleration * Sin(rotation)
			speedY -= acceleration * Cos(rotation)
		End
		
		If KeyDown(KEY_S)
			speedX -= acceleration * Sin(rotation)
			speedY += acceleration * Cos(rotation)
		End
		
		trueSpeed = Sqrt((speedX * speedX) + (speedY * speedY))
		
		If trueSpeed > 0
			speedX -= (speedX / trueSpeed) * deceleration
			speedY -= (speedY / trueSpeed) * deceleration
		End
		
		If trueSpeed > 5
			speedX += (speedX / trueSpeed) * (5 - trueSpeed)
			speedY += (speedY / trueSpeed) * (5 - trueSpeed)
		Endif
		
		positionX += speedX
		positionY += speedY
		
		If positionX < 0 Then positionX = 0 
		If positionX > 1000 Then positionX = 1000
		
		If positionY < 50 Then positionY = 50
		If positionY > 600 Then positionY = 600
		
		If KeyHit(KEY_SPACE)
		
			projectiles.AddLast( New Projectile() )
			
		End

	End
	
	Method Reset()
	
		positionX = origPositionX
		positionY = origPositionY
		speedX = 0
		speedY = 0
		rotation = 0
	
	End
	
	Method Draw()
	
		DrawImage(spaceshipSprite, positionX, positionY, -rotation, 1, 1, 0)
		
	End

End

Class Projectile
	
	Field projectileSprite:Image = LoadImage("projectiles.png", 1, Image.MidHandle)
	
	Field positionX:Float
	Field positionY:Float
	
	Field speedX:Float
	Field speedY:Float
	
	Field rotation:Float
	
	Field trueSpeed:Float = 8
	
	Method New()
	
		speedX = (trueSpeed * Cos(rotation))
		speedY = (trueSpeed * Sin(rotation))
		positionX = theSB.Player.positionX
		positionY = theSB.Player.positionY
		rotation = theSB.Player.rotation
	
	End 
	
	Method Draw()
		
		DrawImage(projectileSprite, positionX, positionY, -rotation, 1, 1, 0)
		
	End
	
	Method Update()
	
		positionX += speedX
		positionY += speedY
		
		If positionX > 1000 Or positionX < 0 Or positionY > 600 Or positionY < 50
		
			projectiles.Remove(Self) 
			
		End
	
	End
		

End
 
Posted 2 months ago #3
Gerry Quinn

Another problem I just noticed glancing at the code: you are loading a copy of the same image into each projectile. You only want one image for all projectiles. Again, can be a global.

 
Posted 2 months ago #4
Crispy

Thank you so much! I would've never been able to see what I did wrong on my own.

 
Posted 2 months ago #5
Crispy

Just another quick question, when you say it doesn't run as it isn't creating projectiles, is that because simply adding a new projectile to the list does not create an object of the class? In my mind it should but I cant understand why it can't now create projectiles.

 
Posted 2 months ago #6
Gerry Quinn

Sorry, my bad - I don't have your images and when I replaced them with basic graphics I missed some, so it was bugging out. I think the version below is running more or less as intended now - at least the spaceship moves and shoots...

Import mojo
Import extended

#GLFW_WINDOW_WIDTH=1000
#GLFW_WINDOW_HEIGHT=600


Function Main()
	theSB = New StarshipBastion()
End

Const STATE_MENU:Int = 0
Const STATE_OPTIONS:Int = 1
Const STATE_CONTROLS:Int = 2
Const STATE_GAME:Int = 3
Const STATE_DEATH:Int = 4
Global projectiles : List<Projectile>
Global theSB:StarshipBastion


Class StarshipBastion Extends App
	
	Field gameState:Int = STATE_MENU
	Field Test1:Image
	Field Test2:Image
	Field Test3:Image
	Field background:Image
	Field title:Image
	Field menu:Image
	Field random:Bool = False
	Field spaceship:Image
	Field pirate:Image
	Field Player:Spaceship
	
	
	Method OnCreate()
	
		SetUpdateRate(60)
		Test1 = LoadImage ("TestImage.png")
		Test2 = LoadImage ("TestImage2.png")
		Test3 = LoadImage ("TestImage3.png")
		background = LoadImage ("background.png")
		title = LoadImage ("title.png")
		menu = LoadImage ("menu2.png")
		pirate = LoadImage ("pirate.png")
		Player = New Spaceship
		projectiles = New List< Projectile >()
	End
	
	Method OnUpdate()
		Select gameState
			Case STATE_MENU
				If KeyHit(KEY_ENTER)
					gameState = STATE_GAME
				End
			Case STATE_OPTIONS
			
			Case STATE_CONTROLS
			
			Case STATE_GAME
			
				If KeyHit(KEY_ENTER)Then random = True
				If KeyHit(KEY_R) Then Player.Reset()
				
				For Local projectile:= Eachin projectiles
				
					projectile.Update()
					
				Next
				
				Player.Update()
			
			Case STATE_DEATH
			
		End
	End
	
	Method OnRender()
		Cls(0, 0, 0)
		
		Select gameState
			Case STATE_MENU
			
				DrawImage(menu, 0, 0)
				DrawText("Press Enter to Play", 320, 400, 0.5)
				
			Case STATE_OPTIONS
			
			Case STATE_CONTROLS
			
			Case STATE_GAME
			
				
				Cls(255, 255, 255)
				'DrawImage(background, 0, 0, 0, 1, 1, 0)
				 
				For Local projectile:= Eachin projectiles
				
					projectile.Draw()
				
				Next
				
				Player.Draw()
			
			Case STATE_DEATH
		End
	End
End

Class Vector                                                                    'TO REMOVE?'
	
	Field x:Float
	Field y:Float
	
	Method New(x:Float = 0, y:Float = 0)
		Set(x, y)
	End
	
	Method Set(x:Float, y:Float)
		Self.x = x
		Self.y = y
	End
End

Class Spaceship

	Field spaceshipSprite:Image = LoadImage ("Spaceship.png", 1, Image.MidHandle)
	
	Field rotation:Float
	
	Field turnSpeed:Float = 0
	
	Const turnAcceleration:Float = 1.4
	Const turnDeceleration:Float = 0.4
	
	Field positionX:Float = 100
	Field positionY:Float = 50
	
	Field origPositionX:Float = 100
	Field origPositionY:Float = 100
	
	Field speedX:Float = 0
	Field speedY:Float = 0
	Field trueSpeed:Float = 0
	
	Const acceleration:Float = 0.2
	Const deceleration:Float = 0.05
	
	Method Update() 
	
		If KeyDown(KEY_D) 
			turnSpeed += turnAcceleration
		End
		
		If KeyDown(KEY_A)
			turnSpeed -= turnAcceleration
		End
		
		If turnSpeed > 5 Then turnSpeed = 5
		If turnSpeed < -5 Then turnSpeed = -5
		
		rotation += turnSpeed
		
		If rotation > 360 Then rotation -= 360
		If rotation < 0 Then rotation += 360
		
		If turnSpeed > turnDeceleration
			turnSpeed -= turnDeceleration
		End
		
		If turnSpeed < -turnDeceleration 
			turnSpeed += turnDeceleration
		End
			
		If turnSpeed < turnDeceleration And turnSpeed > -turnDeceleration 
			turnSpeed = 0
		End
		
		If KeyDown(KEY_W) 
			speedX += acceleration * Sin(rotation)
			speedY -= acceleration * Cos(rotation)
		End
		
		If KeyDown(KEY_S)
			speedX -= acceleration * Sin(rotation)
			speedY += acceleration * Cos(rotation)
		End
		
		trueSpeed = Sqrt((speedX * speedX) + (speedY * speedY))
		
		If trueSpeed > 0
			speedX -= (speedX / trueSpeed) * deceleration
			speedY -= (speedY / trueSpeed) * deceleration
		End
		
		If trueSpeed > 5
			speedX += (speedX / trueSpeed) * (5 - trueSpeed)
			speedY += (speedY / trueSpeed) * (5 - trueSpeed)
		Endif
		
		positionX += speedX
		positionY += speedY
		
		If positionX < 0 Then positionX = 0 
		If positionX > 1000 Then positionX = 1000
		
		If positionY < 50 Then positionY = 50
		If positionY > 600 Then positionY = 600
		
		If KeyHit(KEY_SPACE)
	
			projectiles.AddLast( New Projectile() )
			
		End

	End
	
	Method Reset()
	
		positionX = origPositionX
		positionY = origPositionY
		speedX = 0
		speedY = 0
		rotation = 0
	
	End
	
	Method Draw()
	
		'DrawImage(spaceshipSprite, positionX, positionY, -rotation, 1, 1, 0)
		SetColor( 0, 255, 0 )
		DrawCircle( positionX, positionY, 4.0 )
	End

End

Class Projectile
	
	Field projectileSprite:Image = LoadImage("projectiles.png", 1, Image.MidHandle)
	
	Field positionX:Float
	Field positionY:Float
	
	Field speedX:Float
	Field speedY:Float
	
	Field rotation:Float
	
	Field trueSpeed:Float = 8
	
	Method New()
	
		speedX = (trueSpeed * Cos(rotation))
		speedY = (trueSpeed * Sin(rotation))
		positionX = theSB.Player.positionX
		positionY = theSB.Player.positionY
		rotation = theSB.Player.rotation
	
	End 
	
	Method Draw()
		
		'DrawImage(projectileSprite, positionX, positionY, -rotation, 1, 1, 0)
		SetColor( 255, 0, 0 )
		DrawCircle( positionX, positionY, 2.0 )
		
	End
	
	Method Update()

		positionX += speedX
		positionY += speedY
		
		If positionX > 1000 Or positionX < 0 Or positionY > 600 Or positionY < 50
		
			'projectiles.Remove(Self) 
			
		End
	
	End
		

End
 
Posted 2 months ago #7
Crispy

Seems to only shoot in a single direction, will look into it. It also crashes calling line 263/99. Possibly because it should be theSB.projectile.draw() ?

*Edit* It crashes when using the actual graphics. Using circles works though only with the single direction shooting.

 
Posted 2 months ago #8
Gerry Quinn

Well, there's something wrong with your images, I would imagine - check out the bananas for examples of image use. It's pretty straightforward. For now, load them all in OnCreate(). And print out the width of each after loading, to make sure they are properly loaded. I'd be surprised if that isn't where the problem lies.

EDIT: you can make them globals, or fields of the app - either way they can be accessed easily and you won't have unwanted extra copies. There are reasons why you might choose to have images belong to other classes, but keep things simple to start with.

 
Posted 2 months ago #9
Crispy

Sorry for the long delay, I've been away and my laptop broke on the second day of my trip. I managed to fix the game crashing, and the projectile images are being loaded! The only issue I'm having now is that when the projectiles are fired, both the spaceship and the projectiles colours become inverted. If you'd still be willing to help then I could send you the files? Thanks!!

Edit: Fixed! I've been keeping the circles loading just in case, but after removing them and setcolour everything is working. :)