Long Solo Project (working title)
This is an ongoing solo project that I am working on. This game is a turn base strategy game where units actions are based on their frame data, kind of like a fighting game. All the units attacks will be have an animation with an amount of startup, active, and recovery frames. When a unit performs an attack or action, that unit will perform that action until the animation is finished and then it can act again. As such, this system does not have a strict turn order or rounds. All the unit act and animate at the same time and who goes next is determined by who gets done with their animation first. A unit can also get hit out of their attack animation if they get hit during their startup or recovery frames, which would apply hit stun to that unit.
This is a code sample from the project. It is the C# code for the units in the game.
using UnityEngine; using System.Collections; using System.Collections.Generic; using UnityEngine.UI; using System.Linq; public class BattleManager : MonoBehaviour { public static BattleManager Instance { get; private set; } [HideInInspector] public bool notPaused = true; public List<Unit> guys; public List<Unit> goodGuys; public List<Unit> badGuys; //UI stuff public Text pauseText; public Text actingUnitText; public GameObject attackPanel; public Text[] attackButtons; public GraphManager graphManager; Queue<Unit> actingUnits; Unit actingUnit; bool findingMove = false; bool findingAttack = false; bool findingAttackDirection = false; int currentMainAttack; Camera cam; // Battle Commands Stuff int timeStamp; List<BattleCommand> battleCommands; // Debug bool forcePauser = false; private void Awake() { if (Instance != null) { DestroyImmediate(gameObject); return; } Instance = this; notPaused = true; actingUnits = new Queue<Unit>(); cam = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<Camera>(); battleCommands = new List<BattleCommand>(); } void Update() { // If there is still units in acting units or if thier is a current actingUnit if (forcePauser == false) { if (actingUnits.Count > 0 || actingUnit != null) { notPaused = false; pauseText.text = "Paused"; if (actingUnit == null) { actingUnit = actingUnits.Dequeue(); if (!actingUnit.IsIdleAnimation() || actingUnit.HasActivePath() || actingUnit.HasHitStun()) { actingUnit = null; } } if (actingUnit != null) { actingUnitText.text = ("The Current Acting Unit is: " + actingUnit.name); if (goodGuys.Contains(actingUnit)) { if (findingMove) { if (Input.GetMouseButtonDown(0)) { RaycastHit2D hit; hit = Physics2D.Raycast(new Vector2(cam.ScreenToWorldPoint(Input.mousePosition).x, cam.ScreenToWorldPoint(Input.mousePosition).y), Vector2.zero, 0f, 1 << 10 | 1 << 11); if (hit) { if (hit.collider.gameObject.layer == 10) { Node goal = hit.collider.gameObject.GetComponent<Node>(); Node[] returnPath = actingUnit.GetPathAndMove(goal); BattleCommand battleCommand = AddNewBattleCommand(actingUnit, timeStamp, returnPath, goal, null); GraphToMovementGraph(battleCommand); if (returnPath.Length > 0) { findingMove = false; actingUnit = null; } } } } } if (findingAttack) { attackPanel.SetActive(true); int length = actingUnit.attackManager.mainAttacks.Length; for (int i = 0; i < length; i++) { attackButtons[i].text = actingUnit.attackManager.mainAttacks[i]; } if (findingAttackDirection) { //print ("findingAttackDirection"); if (Input.GetMouseButtonDown (0)) { //print ("someone pressed the button"); RaycastHit2D hit; hit = Physics2D.Raycast (new Vector2 (cam.ScreenToWorldPoint (Input.mousePosition).x, cam.ScreenToWorldPoint (Input.mousePosition).y), Vector2.zero, 0f, 1 << 10 | 1 << 11); bool hitCardnalNode = false; Node attackNode = hit.collider.gameObject.GetComponent<Node> (); if (hit) { print ("hit a node"); foreach (Node node in actingUnit.currentNode.cardnalConnections) { if (attackNode == node) { hitCardnalNode = true; } } } if (hitCardnalNode) { print ("hitCardnalNode is not null"); Vector2 attackDir = attackNode.transform.position - actingUnit.currentNode.transform.position; attackDir.Normalize (); print ("attackNode.transform.position " + attackNode.transform.position); print ("actingUnit.currentNode.position " + actingUnit.currentNode.transform.position); print (attackDir); if (attackDir == new Vector2 (1, 0)) { GetAttack (Attack.Direction.RIGHT); } else if (attackDir == new Vector2 (-1, 0)) { GetAttack (Attack.Direction.LEFT); } else if (attackDir == new Vector2 (0, 1)) { print ("attacking up"); GetAttack (Attack.Direction.UP); } else if (attackDir == new Vector2 (0, -1)) { GetAttack (Attack.Direction.DOWN); } } } } } else { attackPanel.SetActive(false); } } else if (badGuys.Contains(actingUnit)) { BattleCommand battleCommand = actingUnit.GetComponent<BattleAI>().DoBattleCommand(actingUnit, timeStamp); AddNewBattleCommand(battleCommand); GraphToMovementGraph(battleCommand); actingUnit = null; } //Calculate possible collision FindCollisions(); } } // NOTE: the turn system is getting better // be careful of else statements. understand when in a frame the game is // making its checks. some checks are being made on the next frame instead of on // the same frame. if (actingUnit == null) { notPaused = true; timeStamp++; graphManager.ChangeLowestPossibleFrame(timeStamp); } } else { notPaused = false; } if (Input.GetKeyDown(KeyCode.P)) { DebugForcePause(true); } } void LateUpdate() { //print("Battle Manager Late Update"); // NOTE: If the game is notPaused, then their is no current acting units and I need to // search for some if (notPaused) { pauseText.text = "Not Paused"; if (actingUnits.Count == 0) { EnqueueUnits(guys); } } } void FindCollisions() { // grab a unit foreach (Unit unit in guys) { // grab a unit to compare the first unit to foreach (Unit testunit in guys) { if (testunit != unit) // make sure we are not testing units against themselves { // make sure they have graphs if (unit.movementGraph != null && testunit.movementGraph != null) { if (unit.movementGraph.Count > 0 && testunit.movementGraph.Count > 0) { int unitStartingIndex = 0; int testunitStartingIndex = 0; bool breakTime = false; for (int ui = 0; ui < unit.movementGraph.Count; ++ui) { for (int ti = 0; ti < testunit.movementGraph.Count; ++ti) { if (unit.movementGraph[ui].Item1 == testunit.movementGraph[ti].Item1) { unitStartingIndex = ui; testunitStartingIndex = ti; breakTime = true; break; } if (breakTime) { break; } } } while (unit.movementGraph.Count - 1 > unitStartingIndex && testunit.movementGraph.Count - 1 >= testunitStartingIndex) { Node unitNode = unit.movementGraph[unitStartingIndex].Item2; Node testunitNode = testunit.movementGraph[testunitStartingIndex].Item2; Node testunitFramePrev = testunit.movementGraph[testunitStartingIndex].Item2; // NOTE(barret): we need to get previous node, not the frame for (int graphIndex = testunitStartingIndex; graphIndex > 0; --graphIndex) { Node test = testunit.movementGraph[graphIndex].Item2; if (test != testunitFramePrev) { testunitFramePrev = testunit.movementGraph[graphIndex].Item2; } } if (unitNode == testunitNode) { unit.FindFirstCollisionNode(unitNode); testunit.FindFirstCollisionNode(testunitNode); break; } else if (unitNode == testunitFramePrev) { unit.FindFirstCollisionNode(unitNode); testunit.FindFirstCollisionNode(testunitFramePrev); break; } unitStartingIndex++; testunitStartingIndex++; } } } } } } } void GraphToMovementGraph(BattleCommand battleCommand) { actingUnit.movementGraph = CalculateAllFuturePositionsByFrame(battleCommand); if (actingUnit.movementGraph.Count > 0) { //Figure out how to do this now int finalFrame = actingUnit.movementGraph.Last().Item1; int actingUnitIndex = guys.IndexOf(actingUnit); graphManager.TestForHighestPossibleFrameChange(finalFrame); graphManager.sliders[actingUnitIndex].value = finalFrame; } } public void DebugForcePause(bool doIt) { if (doIt) { forcePauser = true; print("Force Pausing"); } } private void EnqueueUnits(List<Unit> unitGroup) { foreach (Unit unit in unitGroup) { if (unit.IsIdleAnimation() && !unit.HasActivePath() && !unit.HasHitStun()) { actingUnits.Enqueue(unit); } } } public void MakeMoveCommand() { if (actingUnit != null) { findingMove = true; findingAttack = false; } } public void MakeAttackCommand() { if (actingUnit != null) { if (actingUnit.IsIdleAnimation()) { findingAttack = true; findingMove = false; } } } public void ChoseAttack(int mainAttackNumber) { findingAttackDirection = true; currentMainAttack = mainAttackNumber; } void GetAttack(Attack.Direction dir) { AttackManager attackManager = GetComponent<AttackManager> (); for(int attackIndex = 0; attackIndex < attackManager.attacks.Length; attackIndex++) { print ("attackIndex " + attackIndex); Attack attack = attackManager.attacks[attackIndex]; if (attack.mainAttackFamily == attackManager.mainAttacks[currentMainAttack]) { if (attack.direction == dir) { ChoseAttack (attackIndex); } } } } void SendAttack(int attackNumber) { Attack newAttack = actingUnit.Attack(attackNumber); actingUnit = null; findingAttack = false; findingAttackDirection = false; AddNewBattleCommand(actingUnit, timeStamp, null, null, newAttack); } public void RemoveUnit(Unit unit) { guys.Remove(unit); } public BattleCommand AddNewBattleCommand(Unit unit, int time, Node[] path, Node goal, Attack attack) { BattleCommand newCommand = new BattleCommand(); newCommand.unit = unit; newCommand.timeStamp = time; newCommand.path = path; newCommand.goal = goal; newCommand.attack = attack; battleCommands.Add(newCommand); return (newCommand); } void AddNewBattleCommand(BattleCommand battleCommand) { battleCommands.Add(battleCommand); } public Node CalculateNodeOnFrame(BattleCommand command, int frame) { Node nodeToFrame = null; Unit unit = command.unit; Node futureCurrentNodes = unit.currentNode; if (command.path.Length > 0) { int startingTimeSteps = timeStamp; Vector2 futurePositions = new Vector2(unit.transform.position.x, unit.transform.position.y); Node futureFromNode = unit.fromNode; Node[] futureActivePath = command.path; int futureActivePathIndex = 0; Node futureActiveNode = futureActivePath[futureActivePathIndex]; for (int currentFrame = startingTimeSteps; currentFrame != startingTimeSteps + frame; currentFrame++) { Vector2 moveDir = futureActiveNode.gameObject.transform.position - futureFromNode.gameObject.transform.position; futurePositions += (moveDir * Time.deltaTime * unit.baseSpeed); float radius = 0.1f; Vector2 pV2 = futurePositions; Vector2 tV2 = futureActiveNode.gameObject.transform.position; float d2 = Unit.DistanceFormula(pV2, tV2); float r2 = radius * radius; if (d2 < r2) { futureCurrentNodes = futureActiveNode; futureFromNode = futureCurrentNodes; if (futureCurrentNodes == unit.goalNode) { print("frame is too late. path already ended"); nodeToFrame = futureCurrentNodes; break; } futureActivePathIndex++; futureActiveNode = futureActivePath[futureActivePathIndex]; } nodeToFrame = futureCurrentNodes; } } return (nodeToFrame); } List<Tuple<int, Node>> CalculateAllFuturePositionsByFrame(BattleCommand command) { List<Tuple<int, Node>> frameToNodeList = new List<Tuple<int, Node>>(); Unit unit = command.unit; Node futureCurrentNodes = unit.currentNode; if (command.path != null) { int startingTimeSteps = timeStamp; Vector2 futurePositions = new Vector2(unit.transform.position.x, unit.transform.position.y); Node futureFromNode = unit.fromNode; Node[] futureActivePath = command.path; int futureActivePathIndex = 0; Node futureActiveNode = futureActivePath[futureActivePathIndex]; futureActivePathIndex++; int currentFrame = startingTimeSteps; bool running = true; while(running) { Vector2 moveDir = futureActiveNode.gameObject.transform.position - futureFromNode.gameObject.transform.position; futurePositions += (moveDir * Time.deltaTime * unit.baseSpeed); float radius = 0.1f; Vector2 pV2 = futurePositions; Vector2 tV2 = futureActiveNode.gameObject.transform.position; float d2 = Unit.DistanceFormula(pV2, tV2); float r2 = radius * radius; if (d2 < r2) { futurePositions = futureActiveNode.transform.position; futureCurrentNodes = futureActiveNode; futureFromNode = futureCurrentNodes; if (futureCurrentNodes == command.goal) { Tuple<int, Node> newItem = new Tuple<int,Node>(currentFrame, futureCurrentNodes); frameToNodeList.Add(newItem); running = false; } if (running == true) { futureActiveNode = futureActivePath[futureActivePathIndex]; futureActivePathIndex++; } } if (running) { Tuple<int, Node> newItem = new Tuple<int, Node>(currentFrame, futureCurrentNodes); frameToNodeList.Add(newItem); currentFrame++; } } } return (frameToNodeList); } void OnDrawGizmos() { if (actingUnit != null) { Gizmos.color = Color.red; Gizmos.DrawWireCube(actingUnit.gameObject.transform.position, new Vector3(actingUnit.currentNode.diameter, actingUnit.currentNode.diameter, 0)); } } } public class BattleCommand { public Unit unit; public int timeStamp; public Node[] path; public Node goal; public Attack attack; public BattleCommand() { } public BattleCommand(Unit u, int t, Node[] p, Node g, Attack a) { unit = u; timeStamp = t; path = p; goal = g; attack = a; } }
Knight Arena
Knight Arena is a solo project that I completed in a week. I made the game in Löve2D, coding in LUA. The game is a 4 player competitive game where each player tries to kill the other players for points by charging into the back or sides of the other players.
tile = {} map={ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, } player1 = {id = "player1", x, y, img, width, height, speed, facing = {x,y}, canMove = true, isMovingX = false, isMovingY = false, score = 0, isCharging = false, chargeTimerStart = 0, chargeTimer = 0.3, isRebounding = false, reboundTimerStart = 0, reboundTimer = 0.5, isDead = false, deathTimerStart = 0, deathTimer = 2} player2 = {id = "player2", x, y, img, width, height, speed, facing = {x,y}, canMove = true, isMovingX = false, isMovingY = false, score = 0, isCharging = false, chargeTimerStart = 0, chargeTimer = 0.3, isRebounding = false, reboundTimerStart = 0, reboundTimer = 0.5, isDead = false, deathTimerStart = 0, deathTimer = 2} player3 = {id = "player3", x, y, img, width, height, speed, facing = {x,y}, canMove = true, isMovingX = false, isMovingY = false, score = 0, isCharging = false, chargeTimerStart = 0, chargeTimer = 0.3, isRebounding = false, reboundTimerStart = 0, reboundTimer = 0.5, isDead = false, deathTimerStart = 0, deathTimer = 2} player4 = {id = "player4", x, y, img, width, height, speed, facing = {x,y}, canMove = true, isMovingX = false, isMovingY = false, score = 0, isCharging = false, chargeTimerStart = 0, chargeTimer = 0.3, isRebounding = false, reboundTimerStart = 0, reboundTimer = 0.5, isDead = false, deathTimerStart = 0, deathTimer = 2} players = {player1, player2, player3, player4} spawnPoint1 = {x = 32, y = 32, width = 32, height = 32} spawnPoint2 = {x = 640, y = 32, width = 32, height = 32} spawnPoint3 = {x = 32, y = 640, width = 32, height = 32} spawnPoint4 = {x = 640, y = 640, width = 32, height = 32} spawnPoints = {spawnPoint1, spawnPoint2, spawnPoint3, spawnPoint4} killPoints = 10 joysticks = {} playArea = {x = 32, y = 32, width = (love.graphics.getWidth( ) - 64), height = (love.graphics.getHeight( ) - 64) } function draw_map() for y = 1, 20, 1 do for x = 1, 20, 1 do love.graphics.draw(tile[map[x][y]], x * 32, y * 32) end end end -- Collision detection function. -- Returns true if two boxes overlap, false if they don't -- x1,y1 are the left-top coords of the first box, while w1,h1 are its width and height -- x2,y2,w2 & h2 are the same, but for the second box function CheckCollision(x1,y1,w1,h1, x2,y2,w2,h2) return x1 < x2+w2 and x2 < x1+w1 and y1 < y2+h2 and y2 < y1+h1 end function ResetBoolsAndTimers(player) player.isCharging = false player.chargeTimerStart = 0 player.isRebounding = false player.reboundTimerStart = 0 --player.canMove = true end function SpawnPointCollision() print("entered SpawnPointCollision") --print(#spawnPoints) for u = 1, #spawnPoints, 1 do local locationBad = false local spawnPointu = spawnPoints[u] print("spawnPoint " .. spawnPointu.x) for i = 1, #players, 1 do local playeri = players[i] local hit = CheckCollision( playeri.x, playeri.y, playeri.width, playeri.height, spawnPointu.x, spawnPointu.y, spawnPointu.width, spawnPointu.height) if hit then locationBad = true end end if locationBad == false then return spawnPointu.x, spawnPointu.y end end end function PlayerDeath(player, dt) ResetBoolsAndTimers(player) if player.deathTimerStart < player.deathTimer then player.canMove = false player.deathTimerStart = player.deathTimerStart + (1 * dt) else local spawnX, spawnY = SpawnPointCollision() player.deathTimerStart = 0 player.x = spawnX player.y = spawnY player.canMove = true player.isDead = false end end function PlayerCharge(player, dt) if player.chargeTimerStart < player.chargeTimer then --print("Charge facing " .. player.facing.x .. "," .. player.facing.y) player.x = player.x + player.facing.x * (player.speed * 15) * dt player.y = player.y + player.facing.y * (player.speed * 15) * dt player.canMove = false player.chargeTimerStart = player.chargeTimerStart + (1 * dt) else player.isCharging = false player.chargeTimerStart = 0 player.canMove = true end end function Reboud(player, dt) --print ("I get called for " .. player.id) if player.reboundTimerStart < player.reboundTimer then player.reboundTimerStart = player.reboundTimerStart + (1 * dt) player.x = player.x + (-1 * player.facing.x) * (player.speed * 5) * dt player.y = player.y + (-1 * player.facing.y) * (player.speed * 5) * dt player.canMove = false else player.reboundTimerStart = 0 player.canMove = true player.isRebounding = false end end function ReboundSetUp(playeri, playeru) -- the setup is wront right now -- i need to have players facing be based on where they hit each other. -- not by their current facing -- need to figure out if a value should be set to zero ResetBoolsAndTimers(playeri) ResetBoolsAndTimers(playeru) local priority = nil -- priority is set to whoever is moving and not set if both are moving if (playeri.isMovingX or playeri.isMovingY) then priority = playeri end if (playeru.isMovingX or playeru.isMovingY) and priority == nil then priority = playeru else priority = nil end -- if a player is moving diagonally if(playeri.isMovingX and playeri.isMovingY) then priority = playeri elseif (playeru.isMovingX and playeru.isMovingY) and not (playeri.isMovingX and player.isMovingY) then priority = playeru end -- playeri is set to priority if it is charging if playeri.isCharging then priority = playeri end -- but if playeru is also charging, set priority to no one if playeru.isCharging and (priority == playeri and playeri.isCharging)then if(playeri.isMovingX and player.isMovingY) then --if one is charging diagonally priority = playeri elseif (playeru.isMovingX and playeru.isMovingY) and not (playeri.isMovingX and player.isMovingY) then priority = playeru else -- if neither player is charging diagonally priority = nil end else -- if playeri is not charging, set priority to playeru priority = playeru end if not priority == nil then if priority == playeri then playeru.facing.x = playeri.facing.x * -1 playeru.facing.y = playeri.facing.y * -1 playeri.facing.x = playeri.facing.x * -1 playeri.facing.y = playeri.facing.y * -1 else playeri.facing.x = playeru.facing.x * -1 playeri.facing.y = playeru.facing.y * -1 playeru.facing.x = playeru.facing.x * -1 playeru.facing.y = playeru.facing.y * -1 end else playeri.facing.x = playeri.facing.x * -1 playeri.facing.y = playeri.facing.y * -1 playeru.facing.x = playeru.facing.x * -1 playeru.facing.y = playeru.facing.y * -1 end playeri.isRebounding = true playeru.isRebounding = true end function AreTheyFacingEachOther(playeri, playeru) local Xfacing = false local Yfacing = false if (playeri.facing.x == 1 and playeru.facing.x == -1) or (playeri.facing.x == 1 and playeru.facing.x == -1) or (playeri.facing.x == 0 and playeru.facing.x == 0)then Xfacing = true end if (playeri.facing.y == 1 and playeru.facing.y == -1) or (playeri.facing.y == 1 and playeru.facing.y == -1) or (playeri.facing.y == 0 and playeru.facing.y == 0)then Yfacing = true end if Xfacing == true and Yfacing == true then return true else return false end end function IsOneFacingTheOther(testPlayer, testAgainstPlayer) local Xfacing = false local Yfacing = false if testPlayer.x - testAgainstPlayer.x > 0 and testPlayer.facing.x == -1 then Xfacing = true elseif testPlayer.x - testAgainstPlayer.x < 0 and testPlayer.facing.x == 1 then Xfacing = true elseif testPlayer.facing.x == 0 then Xfacing = true end if testPlayer.y - testAgainstPlayer.y > 0 and testPlayer.facing.y == -1 then Yfacing = true elseif testPlayer.y - testAgainstPlayer.y < 0 and testPlayer.facing.y == 1 then Yfacing = true elseif testPlayer.facing.y == 0 then Yfacing = true end if Xfacing == true and Yfacing == true then return true else return false end end function GivePoint(player) player.score = player.score + killPoints end function PlayerCollision() for i = 1, #players, 1 do for u = 1, #players, 1 do if players[i] ~= players[u] then local playeri = players[i] local playeru = players[u] local hit = CheckCollision( playeri.x, playeri.y, playeri.width, playeri.height, playeru.x, playeru.y, playeru.width, playeru.height) if hit then if playeri.isCharging then --print("I Collided were charging") if IsOneFacingTheOther(playeri, playeru) and not IsOneFacingTheOther(playeru, playeri) then --print("IsOneFacingTheOther works as intended") playeru.isDead = true --print (playeru.isDead) GivePoint(playeri) end elseif playeru.isCharging then if IsOneFacingTheOther(playeru, playeri) and not IsOneFacingTheOther(playeri, playeru) then playeri.isDead = true GivePoint(playeru) end end ReboundSetUp(playeri, playeru) end end end end end function WallCollision(dt) for i = 1, #players, 1 do local player = players[i] --print(player.id) local hit = CheckCollision(player.x, player.y, player.width, player.height, playArea.x, playArea.y, playArea.width, playArea.height) if not hit then ResetBoolsAndTimers(player) --player.isRebounding = true --print ("hit wall") player.isDead = true else --print("not hit will") end end end function DrawPlayers() if not player1.isDead then love.graphics.draw(player1.img, player1.x, player1.y) end if not player2.isDead then love.graphics.draw(player2.img, player2.x, player2.y) end if not player3.isDead then love.graphics.draw(player3.img, player3.x, player3.y) end if not player4.isDead then love.graphics.draw(player4.img, player4.x, player4.y) end end function PlayerStatuses(dt) for i = 1, #players, 1 do local playerWithStatus = players[i] if playerWithStatus.isRebounding then Reboud(playerWithStatus, dt) end if playerWithStatus.isCharging == true then PlayerCharge(playerWithStatus, dt) end if playerWithStatus.isDead == true then PlayerDeath(playerWithStatus, dt) end end end function NewPlayerInput(dt) for i = 1, #joysticks, 1 do local joystick = joysticks[i] --Only gets players with controllers connected local player = players[joystick:getID()] local directionX = joystick:getGamepadAxis("leftx") local directionY = joystick:getGamepadAxis("lefty") if joystick:isGamepadDown("a") then player.isCharging = true end if player.canMove then if joystick:isGamepadDown("dpup") or directionY < -0.5 then player.y = player.y - player.speed * dt player.facing.y = -1 player.isMovingY = true if (not joystick:isGamepadDown("dpleft") and not joystick:isGamepadDown("dpright")) and (not (directionX < -0.5) and not (directionX > 0.5)) then --print ("What about this") player.facing.x = 0 end elseif joystick:isGamepadDown("dpdown") or directionY > 0.5 then player.y = player.y + player.speed * dt player.facing.y = 1 player.isMovingY = true if (not joystick:isGamepadDown("dpleft") and not joystick:isGamepadDown("dpright")) and (not (directionX < -0.5) and not (directionX > 0.5)) then player.facing.x = 0 end else player.isMovingY = false end if joystick:isGamepadDown("dpleft") or directionX < -0.5 then player.x = player.x - player.speed * dt player.facing.x = -1 player.isMovingX = true if (not joystick:isGamepadDown("dpup") and not joystick:isGamepadDown("dpdown")) and (not (directionY < -0.5) and not (directionY > 0.5)) then player.facing.y = 0 end elseif joystick:isGamepadDown("dpright") or directionX > 0.5 then player.x = player.x + player.speed * dt player.facing.x = 1 player.isMovingX = true if (not joystick:isGamepadDown("dpup") and not joystick:isGamepadDown("dpdown")) and (not (directionY < -0.5) and not (directionY > 0.5)) then player.facing.y = 0 end else player.isMovingX = false end end end end function love.load() for i=0,3 do -- change 3 to the number of tile images minus 1. tile[i] = love.graphics.newImage( "imgs/tile"..i..".png" ) end player1.x = 32 player1.y = 32 player1.img = love.graphics.newImage("imgs/player1.png") player1.width = player1.img:getWidth() player1.height = player1.img:getHeight() player1.speed = 64 player1.facing.x = 1 player1.facing.y = -1 player2.x = 640 player2.y = 32 player2.img = love.graphics.newImage("imgs/player2.png") player2.width = player2.img:getWidth() player2.height = player2.img:getHeight() player2.speed = 64 player2.facing.x = -1 player2.facing.y = 1 player3.x = 32 player3.y = 640 player3.img = love.graphics.newImage("imgs/player3.png") player3.width = player3.img:getWidth() player3.height = player3.img:getHeight() player3.speed = 64 player3.facing.x = -1 player3.facing.y = 1 player4.x = 640 player4.y = 640 player4.img = love.graphics.newImage("imgs/player4.png") player4.width = player4.img:getWidth() player4.height = player4.img:getHeight() player4.speed = 64 player4.facing.x = -1 player4.facing.y = 1 local joystickcount = love.joystick.getJoystickCount() print("The amount of joysticks is " .. joystickcount) joysticks = love.joystick.getJoysticks( ) for i = 1, #joysticks, 1 do id, instanceid = joysticks[i]:getID() print("This controller is " .. id) end end function love.update(dt) PlayerCollision(dt) WallCollision(dt) NewPlayerInput(dt) PlayerStatuses(dt) end function love.draw() draw_map() DrawPlayers() end