Swarm game

Created in 2014, published on 17/01/2023


Here is a gameplay image of the game where the leader in red is being chased by a swarm of other circles. The squares are obstacles which the swarm, including the leader, needs to go around. The goal is to move maximum amount of circles from one end of a level to the other while the obstacles scroll by.



gui

/* GUI.scala */

package game.gui
import game._

import scala._

import org.eclipse.swt._
import org.eclipse.swt.events._
import org.eclipse.swt.graphics._
import org.eclipse.swt.widgets._

object GUI {
	def main(args: Array[String]): Unit = {
		Game.simulationLoop()
        
        var display = new Display()
        var shell = new Shell(display)
        
        display.asyncExec(new Runnable() {
            def run(): Unit = {
                if (!display.isDisposed()) {
                    shell.addMouseMoveListener(new MouseMoveListener() {
                        def mouseMove(event: MouseEvent): Unit = {
                            Game.eventLoop("MouseMoved", event.x, event.y, true)
                        }
                    })
                }
            }
        })
        
        shell.setMinimumSize(Game.level.getSize.getX.toInt, Game.level.getSize.getY.toInt)
        shell.pack()
        shell.open()
        
        shell.addPaintListener(new PaintListener() {
            def paintControl(event: PaintEvent): Unit = {
                var gc = event.gc
                
                var red = new Color(event.widget.getDisplay(), 0xFF,0, 0)
                var black = new Color(event.widget.getDisplay(), 0, 0, 0)
            
                if(Game.swarm.getSwarmSize > 0) {
                    val swarmList = Game.swarm.getSwarmList
                    for(i <- 0 until swarmList.length) {
                        if(swarmList(i) == Game.swarm.getLeader) {
                            gc.setForeground(red)
                        }
                        gc.drawOval(swarmList(i).getPosition.getX.toInt, swarmList(i).getPosition.getY.toInt, swarmList(i).radius*2, swarmList(i).radius*2)
                        
                        gc.setForeground(black)
                    }
                }
                
                if(Game.level.getObstacleList.length > 0) {
                    val obstacleList = Game.level.getObstacleList
                    var xList: scala.List[Int] = scala.List()
                    var yList: scala.List[Int] = scala.List()
                    var combinedList: scala.List[Int] = scala.List()
                    for(i <- 0 until obstacleList.length) {
                        for(j <- 0 until obstacleList(i).corners) {
                            xList = xList :+ obstacleList(i).cornerPositions(j).getX.toInt
                            yList = yList :+ obstacleList(i).cornerPositions(j).getY.toInt
                            combinedList = combinedList :+ obstacleList(i).cornerPositions(j).getX.toInt
                            combinedList = combinedList :+ obstacleList(i).cornerPositions(j).getY.toInt
                        }
                        gc.drawPolygon(combinedList.toArray)
                        combinedList = scala.List()
                        xList = scala.List()
                        yList = scala.List()
                    }
                }
                red.dispose()
            }
        })
        
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                shell.redraw()
            }
        }
        display.dispose()
	}
}

GUI.scala includes the main object that creates the window and the components in it, listens to user input and draws the simulation.












/* Game.scala */

package game
import game.gui._
import game.io._
import game.sim._

object Game  {
	
	private var leaderOffsetX: Double = 0
	private var leaderOffsetY: Double = 0
	
	var swarm = new Swarm
	var level = new Level
  
	def eventLoop(event: String, mouseX: Double, mouseY: Double, mouseMoved: Boolean): Unit = {
	  	if(event == "MouseClicked") {
	  		val swarmList = this.swarm.getSwarmList
	  		for(i <- 0 until swarmList.length) {
		  		if(((mouseX - swarmList(i).getPosition.getX) < swarmList(i).radius*2 && (mouseX - swarmList(i).getPosition.getX) > 0) && ((mouseY - swarmList(i).getPosition.getY) < swarmList(i).radius*2 && (mouseY - swarmList(i).getPosition.getY) > 0)) {
			  		if(this.swarm.getLeaderControlMode == "automatic") {
			  			this.swarm.setLeader(i)
			  			this.leaderOffsetX = swarmList(i).getPosition.getX - mouseX
			  			this.leaderOffsetY = swarmList(i).getPosition.getY - mouseY
			  		}
			  		else {
			  			this.swarm.changeLeaderControlMode
			  		}
		  		}
	  		}
	  	}
	  	if(mouseMoved == true && this.swarm.getLeaderControlMode == "manual") {
	  		this.swarm.changeLeaderTarget(mouseX + this.leaderOffsetX, mouseY + this.leaderOffsetY)
	  	}
	}
	
	def simulationLoop(): Unit = {
		File.readTextFile("src/main/scala/preferences/preferences1.txt", "Preferences")
		File.readTextFile("src/main/scala/levels/level3.txt", "Level")
		var simulation = new Thread(new SimulationThread)
		simulation.start
	}
}

Game.scala includes the object that holds information about the game preferences, initiates objects from the sim- and io-packages, runs the simulation thread and interprets user input from the main thread.











/* SimulationThread.scala */

package game
import game.gui._

class SimulationThread extends Runnable {
	def run(): Unit = {
		while(true) {
			Game.level.updateBackground
			Game.swarm.updateMovement
			Game.swarm.calculateCollisions(Game.level)
			Game.swarm.checkIfLostSwarmMember
			
			Thread.sleep(20)
		}
	}
}

SimulationThread.scala ...